gsk: Drop the gl renderer
authorMatthias Clasen <mclasen@redhat.com>
Sat, 21 Aug 2021 02:50:41 +0000 (22:50 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Sat, 21 Aug 2021 02:58:30 +0000 (22:58 -0400)
ngl supports all the same platforms as gl
now, and has seen more improvements in the
last cycle.

57 files changed:
demos/node-editor/node-editor-window.c
gsk/gl/glutilsprivate.h [deleted file]
gsk/gl/gskgldriver.c [deleted file]
gsk/gl/gskgldriverprivate.h [deleted file]
gsk/gl/gskglglyphcache.c [deleted file]
gsk/gl/gskglglyphcacheprivate.h [deleted file]
gsk/gl/gskgliconcache.c [deleted file]
gsk/gl/gskgliconcacheprivate.h [deleted file]
gsk/gl/gskglimage.c [deleted file]
gsk/gl/gskglimageprivate.h [deleted file]
gsk/gl/gskglnodesample.c [deleted file]
gsk/gl/gskglnodesampleprivate.h [deleted file]
gsk/gl/gskglprofiler.c [deleted file]
gsk/gl/gskglprofilerprivate.h [deleted file]
gsk/gl/gskglrenderer.c [deleted file]
gsk/gl/gskglrenderer.h [deleted file]
gsk/gl/gskglrendererprivate.h [deleted file]
gsk/gl/gskglrenderops.c [deleted file]
gsk/gl/gskglrenderopsprivate.h [deleted file]
gsk/gl/gskglshaderbuilder.c [deleted file]
gsk/gl/gskglshaderbuilderprivate.h [deleted file]
gsk/gl/gskglshadowcache.c [deleted file]
gsk/gl/gskglshadowcacheprivate.h [deleted file]
gsk/gl/gskgltextureatlas.c [deleted file]
gsk/gl/gskgltextureatlasprivate.h [deleted file]
gsk/gl/opbuffer.c [deleted file]
gsk/gl/opbuffer.h [deleted file]
gsk/gl/resources/blend.glsl [deleted file]
gsk/gl/resources/blit.glsl [deleted file]
gsk/gl/resources/blur.glsl [deleted file]
gsk/gl/resources/border.glsl [deleted file]
gsk/gl/resources/color.glsl [deleted file]
gsk/gl/resources/color_matrix.glsl [deleted file]
gsk/gl/resources/coloring.glsl [deleted file]
gsk/gl/resources/conic_gradient.glsl [deleted file]
gsk/gl/resources/cross_fade.glsl [deleted file]
gsk/gl/resources/custom.glsl [deleted file]
gsk/gl/resources/inset_shadow.glsl [deleted file]
gsk/gl/resources/linear_gradient.glsl [deleted file]
gsk/gl/resources/outset_shadow.glsl [deleted file]
gsk/gl/resources/preamble.fs.glsl [deleted file]
gsk/gl/resources/preamble.glsl [deleted file]
gsk/gl/resources/preamble.vs.glsl [deleted file]
gsk/gl/resources/radial_gradient.glsl [deleted file]
gsk/gl/resources/repeat.glsl [deleted file]
gsk/gl/resources/unblurred_outset_shadow.glsl [deleted file]
gsk/gl/stb_rect_pack.c [deleted file]
gsk/gl/stb_rect_pack.h [deleted file]
gsk/gskglshader.c
gsk/gskrenderer.c
gsk/meson.build
gsk/ngl/gskglprofiler.c [new file with mode: 0644]
gsk/ngl/gskglprofilerprivate.h [new file with mode: 0644]
gsk/ngl/gsknglcommandqueueprivate.h
gsk/ngl/gskngltexturelibraryprivate.h
gsk/ngl/stb_rect_pack.c [new file with mode: 0644]
gsk/ngl/stb_rect_pack.h [new file with mode: 0644]

index ce4198d68388930a3747cadb03d364faf82a6f0f..6250857ae6db46301a47b464314c18f5d0c0cb49 100644 (file)
@@ -24,7 +24,6 @@
 #include "gtkrendererpaintableprivate.h"
 
 #include "gsk/gskrendernodeparserprivate.h"
-#include "gsk/gl/gskglrenderer.h"
 #include "gsk/ngl/gsknglrenderer.h"
 #ifdef GDK_WINDOWING_BROADWAY
 #include "gsk/broadway/gskbroadwayrenderer.h"
@@ -778,12 +777,9 @@ node_editor_window_realize (GtkWidget *widget)
                                    NULL,
                                    "Default");
 #endif
-  node_editor_window_add_renderer (self,
-                                   gsk_gl_renderer_new (),
-                                   "OpenGL");
   node_editor_window_add_renderer (self,
                                    gsk_ngl_renderer_new (),
-                                   "NGL");
+                                   "OpenGL");
 #ifdef GDK_RENDERING_VULKAN
   node_editor_window_add_renderer (self,
                                    gsk_vulkan_renderer_new (),
diff --git a/gsk/gl/glutilsprivate.h b/gsk/gl/glutilsprivate.h
deleted file mode 100644 (file)
index f035bda..0000000
+++ /dev/null
@@ -1,317 +0,0 @@
-
-#pragma once
-
-#define SANITY_CHECKS 0
-
-
-
-#define rounded_rect_top_left(r) (GRAPHENE_RECT_INIT(r->bounds.origin.x, \
-                                                     r->bounds.origin.y, \
-                                                     r->corner[0].width, r->corner[0].height))
-
-#define rounded_rect_top_right(r) (GRAPHENE_RECT_INIT(r->bounds.origin.x + r->bounds.size.width - r->corner[1].width, \
-                                                      r->bounds.origin.y, \
-                                                      r->corner[1].width, r->corner[1].height))
-
-#define rounded_rect_bottom_right(r) (GRAPHENE_RECT_INIT(r->bounds.origin.x + r->bounds.size.width - r->corner[2].width, \
-                                                         r->bounds.origin.y + r->bounds.size.height - r->corner[2].height, \
-                                                         r->corner[2].width, r->corner[2].height))
-
-#define rounded_rect_bottom_left(r) (GRAPHENE_RECT_INIT(r->bounds.origin.x, \
-                                                         r->bounds.origin.y + r->bounds.size.height - r->corner[2].height, \
-                                                         r->corner[3].width, r->corner[3].height))
-
-
-#define rounded_rect_corner0(r) rounded_rect_top_left(r)
-#define rounded_rect_corner1(r) rounded_rect_top_right(r)
-#define rounded_rect_corner2(r) rounded_rect_bottom_right(r)
-#define rounded_rect_corner3(r) rounded_rect_bottom_left(r)
-
-#define rounded_rect_corner(r, i) (rounded_rect_corner ##i(r))
-#define graphene_size_non_zero(s) (s->width > 0 && s->height > 0)
-#define rounded_rect_has_corner(r, i) (r->corner[i].width > 0 && r->corner[i].height > 0)
-
-#define rect_contains_point(r, _x, _y) (_x >= (r)->origin.x && _x <= (r)->origin.x + (r)->size.width && \
-                                        _y >= (r)->origin.y && _y <= (r)->origin.y + (r)->size.height)
-
-enum {
-  NINE_SLICE_TOP_LEFT      = 0,
-  NINE_SLICE_TOP_CENTER    = 1,
-  NINE_SLICE_TOP_RIGHT     = 2,
-  NINE_SLICE_LEFT_CENTER   = 3,
-  NINE_SLICE_CENTER        = 4,
-  NINE_SLICE_RIGHT_CENTER  = 5,
-  NINE_SLICE_BOTTOM_LEFT   = 6,
-  NINE_SLICE_BOTTOM_CENTER = 7,
-  NINE_SLICE_BOTTOM_RIGHT  = 8,
-};
-#define NINE_SLICE_SIZE 9 /* Hah. */
-
-typedef struct
-{
-  int texture_id;
-  float x;
-  float y;
-  float x2;
-  float y2;
-} TextureRegion;
-
-static inline bool G_GNUC_PURE
-slice_is_visible (const cairo_rectangle_int_t *r)
-{
-  return (r->width > 0 && r->height > 0);
-}
-
-static inline void
-nine_slice_rounded_rect (const GskRoundedRect  *rect,
-                         cairo_rectangle_int_t *out_rects)
-{
-  const graphene_point_t *origin = &rect->bounds.origin;
-  const graphene_size_t *size = &rect->bounds.size;
-  const int top_height = ceilf (MAX (rect->corner[GSK_CORNER_TOP_LEFT].height,
-                                     rect->corner[GSK_CORNER_TOP_RIGHT].height));
-  const int bottom_height = ceilf (MAX (rect->corner[GSK_CORNER_BOTTOM_LEFT].height,
-                                        rect->corner[GSK_CORNER_BOTTOM_RIGHT].height));
-  const int right_width = ceilf (MAX (rect->corner[GSK_CORNER_TOP_RIGHT].width,
-                                      rect->corner[GSK_CORNER_BOTTOM_RIGHT].width));
-  const int left_width = ceilf (MAX (rect->corner[GSK_CORNER_TOP_LEFT].width,
-                                     rect->corner[GSK_CORNER_BOTTOM_LEFT].width));
-
-  /* Top left */
-  out_rects[0] = (cairo_rectangle_int_t) {
-                   origin->x, origin->y,
-                   left_width, top_height,
-                 };
-
-  /* Top center */
-  out_rects[1] = (cairo_rectangle_int_t) {
-                   origin->x + size->width / 2.0 - 0.5, origin->y,
-                   1, top_height,
-                 };
-
-  /* Top right */
-  out_rects[2] = (cairo_rectangle_int_t) {
-                   origin->x + size->width - right_width, origin->y,
-                   right_width, top_height
-                 };
-
-  /* Left center */
-  out_rects[3] = (cairo_rectangle_int_t) {
-                   origin->x, origin->y + size->height / 2,
-                   left_width, 1,
-                 };
-
-  /* center */
-  out_rects[4] = (cairo_rectangle_int_t) {
-                   origin->x + size->width / 2.0 - 0.5,
-                   origin->y + size->height / 2.0 - 0.5,
-                   1, 1
-                 };
-
-  /* Right center */
-  out_rects[5] = (cairo_rectangle_int_t) {
-                   origin->x + size->width - right_width,
-                   origin->y + (size->height / 2.0) - 0.5,
-                   right_width,
-                   1,
-                 };
-
-  /* Bottom Left */
-  out_rects[6] = (cairo_rectangle_int_t) {
-                   origin->x, origin->y + size->height - bottom_height,
-                   left_width, bottom_height,
-                 };
-
-  /* Bottom center */
-  out_rects[7] = (cairo_rectangle_int_t) {
-                   origin->x + (size->width / 2.0) - 0.5,
-                     origin->y + size->height - bottom_height,
-                   1, bottom_height,
-                 };
-
-  /* Bottom right */
-  out_rects[8] = (cairo_rectangle_int_t) {
-                   origin->x + size->width - right_width,
-                   origin->y + size->height - bottom_height,
-                   right_width, bottom_height,
-                 };
-
-#if SANITY_CHECKS
-  g_assert_cmpfloat (size->width, >=, left_width + right_width);
-  g_assert_cmpfloat (size->height, >=, top_height + bottom_height);
-#endif
-}
-
-static inline void
-nine_slice_grow (cairo_rectangle_int_t *slices,
-                 const int              amount)
-{
-  /* top left */
-  slices[0].x -= amount;
-  slices[0].y -= amount;
-  if (amount > slices[0].width)
-    slices[0].width += amount * 2;
-  else
-    slices[0].width += amount;
-
-  if (amount > slices[0].height)
-    slices[0].height += amount * 2;
-  else
-    slices[0].height += amount;
-
-
-  /* Top center */
-  slices[1].y -= amount;
-  if (amount > slices[1].height)
-    slices[1].height += amount * 2;
-  else
-    slices[1].height += amount;
-
-  /* top right */
-  slices[2].y -= amount;
-  if (amount > slices[2].width)
-    {
-      slices[2].x -= amount;
-      slices[2].width += amount * 2;
-    }
-  else
-    {
-     slices[2].width += amount;
-    }
-
-  if (amount > slices[2].height)
-    slices[2].height += amount * 2;
-  else
-    slices[2].height += amount;
-
-
-
-  slices[3].x -= amount;
-  if (amount > slices[3].width)
-    slices[3].width += amount * 2;
-  else
-    slices[3].width += amount;
-
-  /* Leave Britney^Wcenter alone */
-
-  if (amount > slices[5].width)
-    {
-      slices[5].x -= amount;
-      slices[5].width += amount * 2;
-    }
-  else
-    {
-      slices[5].width += amount;
-    }
-
-
-  /* Bottom left */
-  slices[6].x -= amount;
-  if (amount > slices[6].width)
-    {
-      slices[6].width += amount * 2;
-    }
-  else
-    {
-      slices[6].width += amount;
-    }
-
-  if (amount > slices[6].height)
-    {
-      slices[6].y -= amount;
-      slices[6].height += amount * 2;
-    }
-  else
-    {
-      slices[6].height += amount;
-    }
-
-
-  /* Bottom center */
-  if (amount > slices[7].height)
-    {
-      slices[7].y -= amount;
-      slices[7].height += amount * 2;
-    }
-  else
-    {
-      slices[7].height += amount;
-    }
-
-  if (amount > slices[8].width)
-    {
-      slices[8].x -= amount;
-      slices[8].width += amount * 2;
-    }
-  else
-    {
-      slices[8].width += amount;
-    }
-
-  if (amount > slices[8].height)
-    {
-      slices[8].y -= amount;
-      slices[8].height += amount * 2;
-    }
-  else
-    {
-      slices[8].height += amount;
-    }
-
-#if SANITY_CHECKS
-  {
-    for (int i = 0; i < 9; i ++)
-      {
-        g_assert_cmpint (slices[i].x, >=, 0);
-        g_assert_cmpint (slices[i].y, >=, 0);
-        g_assert_cmpint (slices[i].width, >=, 0);
-        g_assert_cmpint (slices[i].height, >=, 0);
-      }
-
-    /* Rows don't overlap */
-    for (int i = 0; i < 3; i++)
-      {
-        g_assert_cmpint (slices[i * 3 + 0].x + slices[i * 3 + 0].width, <, slices[i * 3 + 1].x);
-      }
-  }
-#endif
-
-}
-
-static inline void
-nine_slice_to_texture_coords (const cairo_rectangle_int_t *slices,
-                              const int                    texture_width,
-                              const int                    texture_height,
-                              TextureRegion               *out_regions)
-{
-  const float fw = (float)texture_width;
-  const float fh = (float)texture_height;
-  int i;
-
-  for (i = 0; i < 9; i++)
-    {
-      out_regions[i] = (TextureRegion) {
-        0, /* Texture id */
-        slices[i].x / fw,
-        1.0 - ((slices[i].y + slices[i].height) / fh),
-        (slices[i].x + slices[i].width)  / fw,
-        1.0 - (slices[i].y / fh),
-      };
-    }
-
-#if SANITY_CHECKS
-  {
-    for (i = 0; i < 9; i++)
-      {
-        const TextureRegion *r = &out_regions[i];
-        g_assert_cmpfloat (r->x, >=, 0);
-        g_assert_cmpfloat (r->x, <=, 1);
-        g_assert_cmpfloat (r->y, >=, 0);
-        g_assert_cmpfloat (r->y, <=, 1);
-
-        g_assert_cmpfloat (r->x, <, r->x2);
-        g_assert_cmpfloat (r->y, <, r->y2);
-      }
-  }
-#endif
-}
diff --git a/gsk/gl/gskgldriver.c b/gsk/gl/gskgldriver.c
deleted file mode 100644 (file)
index 8fe726b..0000000
+++ /dev/null
@@ -1,849 +0,0 @@
-#include "config.h"
-
-#include "gskgldriverprivate.h"
-
-#include "gskdebugprivate.h"
-#include "gskprofilerprivate.h"
-#include "gdk/gdkglcontextprivate.h"
-#include "gdk/gdktextureprivate.h"
-#include "gdk/gdkgltextureprivate.h"
-#include "gdkmemorytextureprivate.h"
-
-#include <gdk/gdk.h>
-#include <epoxy/gl.h>
-
- typedef struct {
-  GLuint fbo_id;
-  GLuint depth_stencil_id;
-} Fbo;
-
-typedef struct {
-  GLuint texture_id;
-  int width;
-  int height;
-  GLuint min_filter;
-  GLuint mag_filter;
-  Fbo fbo;
-  GdkTexture *user;
-  guint in_use : 1;
-  guint permanent : 1;
-
-  /* TODO: Make this optional and not for every texture... */
-  TextureSlice *slices;
-  guint n_slices;
-} Texture;
-
-struct _GskGLDriver
-{
-  GObject parent_instance;
-
-  GdkGLContext *gl_context;
-  GskProfiler *profiler;
-  struct {
-    GQuark created_textures;
-    GQuark reused_textures;
-    GQuark surface_uploads;
-  } counters;
-
-  Fbo default_fbo;
-
-  GHashTable *textures;         /* texture_id -> Texture */
-  GHashTable *pointer_textures; /* pointer -> texture_id */
-
-  const Texture *bound_source_texture;
-
-  int max_texture_size;
-
-  gboolean in_frame : 1;
-};
-
-G_DEFINE_TYPE (GskGLDriver, gsk_gl_driver, G_TYPE_OBJECT)
-
-static void
-upload_gdk_texture (GdkTexture      *source_texture,
-                    int              target,
-                    int              x_offset,
-                    int              y_offset,
-                    int              width,
-                    int              height)
-{
-  cairo_surface_t *surface = NULL;
-  GdkMemoryFormat data_format;
-  const guchar *data;
-  gsize data_stride;
-  gsize bpp;
-
-  g_return_if_fail (source_texture != NULL);
-  g_return_if_fail (x_offset + width <= gdk_texture_get_width (source_texture));
-  g_return_if_fail (y_offset + height <= gdk_texture_get_height (source_texture));
-
-  /* Note: GdkGLTextures are already handled before we reach this and reused as-is */
-
-  if (GDK_IS_MEMORY_TEXTURE (source_texture))
-    {
-      GdkMemoryTexture *memory_texture = GDK_MEMORY_TEXTURE (source_texture);
-      data = gdk_memory_texture_get_data (memory_texture);
-      data_format = gdk_memory_texture_get_format (memory_texture);
-      data_stride = gdk_memory_texture_get_stride (memory_texture);
-    }
-  else
-    {
-      /* Fall back to downloading to a surface */
-      surface = gdk_texture_download_surface (source_texture);
-      cairo_surface_flush (surface);
-      data = cairo_image_surface_get_data (surface);
-      data_format = GDK_MEMORY_DEFAULT;
-      data_stride = cairo_image_surface_get_stride (surface);
-    }
-
-  bpp = gdk_memory_format_bytes_per_pixel (data_format);
-
-  gdk_gl_context_upload_texture (gdk_gl_context_get_current (),
-                                 data + x_offset * bpp + y_offset * data_stride,
-                                 width, height, data_stride,
-                                 data_format, target);
-
-  if (surface)
-    cairo_surface_destroy (surface);
-}
-
-static Texture *
-texture_new (void)
-{
-  return g_slice_new0 (Texture);
-}
-
-static inline void
-fbo_clear (const Fbo *f)
-{
-  if (f->depth_stencil_id != 0)
-    glDeleteRenderbuffers (1, &f->depth_stencil_id);
-
-  glDeleteFramebuffers (1, &f->fbo_id);
-}
-
-static void
-texture_free (gpointer data)
-{
-  Texture *t = data;
-  guint i;
-
-  if (t->user)
-    gdk_texture_clear_render_data (t->user);
-
-  if (t->fbo.fbo_id != 0)
-    fbo_clear (&t->fbo);
-
-  if (t->texture_id != 0)
-    {
-      glDeleteTextures (1, &t->texture_id);
-    }
-  else
-    {
-      g_assert_cmpint (t->n_slices, >, 0);
-
-      for (i = 0; i < t->n_slices; i ++)
-        glDeleteTextures (1, &t->slices[i].texture_id);
-    }
-
-  g_slice_free (Texture, t);
-}
-
-static void
-gsk_gl_driver_set_texture_parameters (GskGLDriver *self,
-                                      int          min_filter,
-                                      int          mag_filter)
-{
-  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
-  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
-
-  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-}
-
-static void
-gsk_gl_driver_finalize (GObject *gobject)
-{
-  GskGLDriver *self = GSK_GL_DRIVER (gobject);
-
-  gdk_gl_context_make_current (self->gl_context);
-
-  g_clear_pointer (&self->textures, g_hash_table_unref);
-  g_clear_pointer (&self->pointer_textures, g_hash_table_unref);
-  g_clear_object (&self->profiler);
-
-  if (self->gl_context == gdk_gl_context_get_current ())
-    gdk_gl_context_clear_current ();
-
-  G_OBJECT_CLASS (gsk_gl_driver_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_gl_driver_class_init (GskGLDriverClass *klass)
-{
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
-  gobject_class->finalize = gsk_gl_driver_finalize;
-}
-
-static void
-gsk_gl_driver_init (GskGLDriver *self)
-{
-  self->textures = g_hash_table_new_full (NULL, NULL, NULL, texture_free);
-
-  self->max_texture_size = -1;
-
-#ifdef G_ENABLE_DEBUG
-  self->profiler = gsk_profiler_new ();
-  self->counters.created_textures = gsk_profiler_add_counter (self->profiler,
-                                                              "created_textures",
-                                                              "Textures created this frame",
-                                                              TRUE);
-  self->counters.reused_textures = gsk_profiler_add_counter (self->profiler,
-                                                             "reused_textures",
-                                                             "Textures reused this frame",
-                                                             TRUE);
-  self->counters.surface_uploads = gsk_profiler_add_counter (self->profiler,
-                                                             "surface_uploads",
-                                                             "Texture uploads from surfaces this frame",
-                                                             TRUE);
-#endif
-}
-
-GskGLDriver *
-gsk_gl_driver_new (GdkGLContext *context)
-{
-  GskGLDriver *self;
-  g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
-
-  self = (GskGLDriver *) g_object_new (GSK_TYPE_GL_DRIVER, NULL);
-  self->gl_context = context;
-
-  return self;
-}
-
-void
-gsk_gl_driver_begin_frame (GskGLDriver *self)
-{
-  g_return_if_fail (GSK_IS_GL_DRIVER (self));
-  g_return_if_fail (!self->in_frame);
-
-  self->in_frame = TRUE;
-
-  if (self->max_texture_size < 0)
-    {
-      glGetIntegerv (GL_MAX_TEXTURE_SIZE, (GLint *) &self->max_texture_size);
-      GSK_NOTE (OPENGL, g_message ("GL max texture size: %d", self->max_texture_size));
-    }
-
-  glBindFramebuffer (GL_FRAMEBUFFER, 0);
-
-  glActiveTexture (GL_TEXTURE0);
-  glBindTexture (GL_TEXTURE_2D, 0);
-
-  glActiveTexture (GL_TEXTURE0 + 1);
-  glBindTexture (GL_TEXTURE_2D, 0);
-
-  glBindVertexArray (0);
-  glUseProgram (0);
-
-  glActiveTexture (GL_TEXTURE0);
-
-#ifdef G_ENABLE_DEBUG
-  gsk_profiler_reset (self->profiler);
-#endif
-}
-
-gboolean
-gsk_gl_driver_in_frame (GskGLDriver *self)
-{
-  return self->in_frame;
-}
-
-void
-gsk_gl_driver_end_frame (GskGLDriver *self)
-{
-  g_return_if_fail (GSK_IS_GL_DRIVER (self));
-  g_return_if_fail (self->in_frame);
-
-  self->bound_source_texture = NULL;
-
-  self->default_fbo.fbo_id = 0;
-
-#ifdef G_ENABLE_DEBUG
-  GSK_NOTE (OPENGL,
-            g_message ("Textures created: %" G_GINT64_FORMAT "\n"
-                     " Textures reused: %" G_GINT64_FORMAT "\n"
-                     " Surface uploads: %" G_GINT64_FORMAT,
-                     gsk_profiler_counter_get (self->profiler, self->counters.created_textures),
-                     gsk_profiler_counter_get (self->profiler, self->counters.reused_textures),
-                     gsk_profiler_counter_get (self->profiler, self->counters.surface_uploads)));
-#endif
-
-  GSK_NOTE (OPENGL,
-            g_message ("*** Frame end: textures=%d",
-                     g_hash_table_size (self->textures)));
-
-  self->in_frame = FALSE;
-}
-
-int
-gsk_gl_driver_collect_textures (GskGLDriver *self)
-{
-  GHashTableIter iter;
-  gpointer value_p = NULL;
-  int old_size;
-
-  g_return_val_if_fail (GSK_IS_GL_DRIVER (self), 0);
-  g_return_val_if_fail (!self->in_frame, 0);
-
-  old_size = g_hash_table_size (self->textures);
-
-  g_hash_table_iter_init (&iter, self->textures);
-  while (g_hash_table_iter_next (&iter, NULL, &value_p))
-    {
-      Texture *t = value_p;
-
-      if (t->user || t->permanent)
-        continue;
-
-      if (t->in_use)
-        {
-          t->in_use = FALSE;
-
-          if (t->fbo.fbo_id != 0)
-            {
-              fbo_clear (&t->fbo);
-              t->fbo.fbo_id = 0;
-            }
-        }
-      else
-        {
-          /* Remove from self->pointer_textures. */
-          /* TODO: Is there a better way for this? */
-          if (self->pointer_textures)
-            {
-              GHashTableIter pointer_iter;
-              gpointer value;
-              gpointer p;
-
-              g_hash_table_iter_init (&pointer_iter, self->pointer_textures);
-              while (g_hash_table_iter_next (&pointer_iter, &p, &value))
-                {
-                  if (GPOINTER_TO_INT (value) == t->texture_id)
-                    {
-                      g_hash_table_iter_remove (&pointer_iter);
-                      break;
-                    }
-                }
-            }
-
-          g_hash_table_iter_remove (&iter);
-        }
-    }
-
-  return old_size - g_hash_table_size (self->textures);
-}
-
-
-GdkGLContext *
-gsk_gl_driver_get_gl_context (GskGLDriver *self)
-{
-  return self->gl_context;
-}
-
-int
-gsk_gl_driver_get_max_texture_size (GskGLDriver *self)
-{
-  if (self->max_texture_size < 0)
-    {
-      if (gdk_gl_context_get_use_es (self->gl_context))
-        return 2048;
-
-      return 1024;
-    }
-
-  return self->max_texture_size;
-}
-
-static Texture *
-gsk_gl_driver_get_texture (GskGLDriver *self,
-                           int          texture_id)
-{
-  Texture *t;
-
-  if (g_hash_table_lookup_extended (self->textures, GINT_TO_POINTER (texture_id), NULL, (gpointer *) &t))
-    return t;
-
-  return NULL;
-}
-
-static Texture *
-create_texture (GskGLDriver *self,
-                float        fwidth,
-                float        fheight)
-{
-  guint texture_id;
-  Texture *t;
-  int width = ceilf (fwidth);
-  int height = ceilf (fheight);
-
-  g_assert (width > 0);
-  g_assert (height > 0);
-
-  if (width > self->max_texture_size ||
-      height > self->max_texture_size)
-    {
-      g_critical ("Texture %d x %d is bigger than supported texture limit of %d; clipping...",
-                  width, height,
-                  self->max_texture_size);
-
-      width = MIN (width, self->max_texture_size);
-      height = MIN (height, self->max_texture_size);
-    }
-
-  glGenTextures (1, &texture_id);
-  t = texture_new ();
-  t->texture_id = texture_id;
-  t->width = width;
-  t->height = height;
-  t->min_filter = GL_NEAREST;
-  t->mag_filter = GL_NEAREST;
-  t->in_use = TRUE;
-  g_hash_table_insert (self->textures, GINT_TO_POINTER (texture_id), t);
-#ifdef G_ENABLE_DEBUG
-  gsk_profiler_counter_inc (self->profiler, self->counters.created_textures);
-#endif
-
-  return t;
-}
-
-static void
-gsk_gl_driver_release_texture (gpointer data)
-{
-  Texture *t = data;
-
-  t->user = NULL;
-}
-
-void
-gsk_gl_driver_slice_texture (GskGLDriver   *self,
-                             GdkTexture    *texture,
-                             TextureSlice **out_slices,
-                             guint         *out_n_slices)
-{
-  const int max_texture_size = gsk_gl_driver_get_max_texture_size (self) / 4; // XXX Too much?
-  const int cols = (texture->width / max_texture_size) + 1;
-  const int rows = (texture->height / max_texture_size) + 1;
-  int col, row;
-  int x = 0, y = 0; /* Position in the texture */
-  TextureSlice *slices;
-  Texture *tex;
-
-  g_assert (texture->width > max_texture_size || texture->height > max_texture_size);
-
-
-  tex = gdk_texture_get_render_data (texture, self);
-
-  if (tex != NULL)
-    {
-      g_assert (tex->n_slices > 0);
-      *out_slices = tex->slices;
-      *out_n_slices = tex->n_slices;
-      return;
-    }
-
-  slices = g_new0 (TextureSlice, cols * rows);
-
-  for (col = 0; col < cols; col ++)
-    {
-      const int slice_width = MIN (max_texture_size, texture->width - x);
-
-      for (row = 0; row < rows; row ++)
-        {
-          const int slice_height = MIN (max_texture_size, texture->height - y);
-          const int slice_index = (col * rows) + row;
-          guint texture_id;
-
-          glGenTextures (1, &texture_id);
-
-#ifdef G_ENABLE_DEBUG
-          gsk_profiler_counter_inc (self->profiler, self->counters.created_textures);
-#endif
-          glBindTexture (GL_TEXTURE_2D, texture_id);
-          gsk_gl_driver_set_texture_parameters (self, GL_NEAREST, GL_NEAREST);
-          upload_gdk_texture (texture, GL_TEXTURE_2D, x, y, slice_width, slice_height);
-
-#ifdef G_ENABLE_DEBUG
-          gsk_profiler_counter_inc (self->profiler, self->counters.surface_uploads);
-#endif
-
-          slices[slice_index].rect = (GdkRectangle){x, y, slice_width, slice_height};
-          slices[slice_index].texture_id = texture_id;
-
-          y += slice_height;
-        }
-
-      y = 0;
-      x += slice_width;
-    }
-
-  /* Allocate one Texture for the entire thing. */
-  tex = texture_new ();
-  tex->width = texture->width;
-  tex->height = texture->height;
-  tex->min_filter = GL_NEAREST;
-  tex->mag_filter = GL_NEAREST;
-  tex->in_use = TRUE;
-  tex->slices = slices;
-  tex->n_slices = cols * rows;
-
-  /* Use texture_free as destroy notify here since we are not inserting this Texture
-   * into self->textures! */
-  gdk_texture_set_render_data (texture, self, tex, texture_free);
-
-  *out_slices = slices;
-  *out_n_slices = cols * rows;
-}
-
-int
-gsk_gl_driver_get_texture_for_texture (GskGLDriver *self,
-                                       GdkTexture  *texture,
-                                       int          min_filter,
-                                       int          mag_filter)
-{
-  Texture *t;
-  GdkTexture *downloaded_texture = NULL;
-  GdkTexture *source_texture;
-
-  if (GDK_IS_GL_TEXTURE (texture))
-    {
-      GdkGLTexture *gl_texture = (GdkGLTexture *) texture;
-      GdkGLContext *texture_context = gdk_gl_texture_get_context (gl_texture);
-
-      if (gdk_gl_context_is_shared (self->gl_context, texture_context))
-        {
-          /* A GL texture from the same GL context is a simple task... */
-          return gdk_gl_texture_get_id (gl_texture);
-        }
-      else
-        {
-          cairo_surface_t *surface;
-
-          /* In this case, we have to temporarily make the texture's context the current one,
-           * download its data into our context and then create a texture from it. */
-          if (texture_context)
-            gdk_gl_context_make_current (texture_context);
-
-          surface = gdk_texture_download_surface (texture);
-          downloaded_texture = gdk_texture_new_for_surface (surface);
-          cairo_surface_destroy (surface);
-
-          gdk_gl_context_make_current (self->gl_context);
-
-          source_texture = downloaded_texture;
-        }
-    }
-  else
-    {
-      t = gdk_texture_get_render_data (texture, self);
-
-      if (t)
-        {
-          if (t->min_filter == min_filter && t->mag_filter == mag_filter)
-            return t->texture_id;
-        }
-
-      source_texture = texture;
-    }
-
-  t = create_texture (self, gdk_texture_get_width (texture), gdk_texture_get_height (texture));
-
-  if (gdk_texture_set_render_data (texture, self, t, gsk_gl_driver_release_texture))
-    t->user = texture;
-
-  gsk_gl_driver_bind_source_texture (self, t->texture_id);
-  gsk_gl_driver_init_texture (self,
-                              t->texture_id,
-                              source_texture,
-                              min_filter,
-                              mag_filter);
-  gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, t->texture_id,
-                                      "GdkTexture<%p> %d", texture, t->texture_id);
-
-  if (downloaded_texture)
-    g_object_unref (downloaded_texture);
-
-  return t->texture_id;
-}
-
-static guint
-texture_key_hash (gconstpointer v)
-{
-  const GskTextureKey *k = (GskTextureKey *)v;
-
-  return GPOINTER_TO_UINT (k->pointer)
-         + (guint)(k->scale_x * 100)
-         + (guint)(k->scale_y * 100)
-         + (guint)k->filter * 2 +
-         + (guint)k->pointer_is_child;
-}
-
-static gboolean
-texture_key_equal (gconstpointer v1, gconstpointer v2)
-{
-  const GskTextureKey *k1 = (GskTextureKey *)v1;
-  const GskTextureKey *k2 = (GskTextureKey *)v2;
-
-  return k1->pointer == k2->pointer &&
-         k1->scale_x == k2->scale_x &&
-         k1->scale_y == k2->scale_y &&
-         k1->filter == k2->filter &&
-         k1->pointer_is_child == k2->pointer_is_child &&
-         (!k1->pointer_is_child || graphene_rect_equal (&k1->parent_rect, &k2->parent_rect));
-}
-
-int
-gsk_gl_driver_get_texture_for_key (GskGLDriver   *self,
-                                   GskTextureKey *key)
-{
-  int id = 0;
-
-  if (G_UNLIKELY (self->pointer_textures == NULL))
-    self->pointer_textures = g_hash_table_new_full (texture_key_hash, texture_key_equal, g_free, NULL);
-
-  id = GPOINTER_TO_INT (g_hash_table_lookup (self->pointer_textures, key));
-
-  if (id != 0)
-    {
-      Texture *t;
-
-      t = g_hash_table_lookup (self->textures, GINT_TO_POINTER (id));
-
-      if (t != NULL)
-        t->in_use = TRUE;
-    }
-
-  return id;
-}
-
-void
-gsk_gl_driver_set_texture_for_key (GskGLDriver   *self,
-                                   GskTextureKey *key,
-                                   int            texture_id)
-{
-  GskTextureKey *k;
-
-  if (G_UNLIKELY (self->pointer_textures == NULL))
-    self->pointer_textures = g_hash_table_new_full (texture_key_hash, texture_key_equal, g_free, NULL);
-
-  k = g_new (GskTextureKey, 1);
-  *k = *key;
-
-  g_hash_table_insert (self->pointer_textures, k, GINT_TO_POINTER (texture_id));
-}
-
-int
-gsk_gl_driver_create_texture (GskGLDriver *self,
-                              float        width,
-                              float        height)
-{
-  Texture *t;
-
-  g_return_val_if_fail (GSK_IS_GL_DRIVER (self), -1);
-
-  t = create_texture (self, width, height);
-
-  return t->texture_id;
-}
-
-void
-gsk_gl_driver_create_render_target (GskGLDriver *self,
-                                    int          width,
-                                    int          height,
-                                    int          min_filter,
-                                    int          mag_filter,
-                                    int         *out_texture_id,
-                                    int         *out_render_target_id)
-{
-  GLuint fbo_id;
-  Texture *texture;
-
-  g_return_if_fail (self->in_frame);
-
-  texture = create_texture (self, width, height);
-  gsk_gl_driver_bind_source_texture (self, texture->texture_id);
-  gsk_gl_driver_init_texture_empty (self, texture->texture_id, min_filter, mag_filter);
-
-  glGenFramebuffers (1, &fbo_id);
-  glBindFramebuffer (GL_FRAMEBUFFER, fbo_id);
-  glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->texture_id, 0);
-
-#if 0
-  if (add_depth_buffer || add_stencil_buffer)
-    {
-      glGenRenderbuffersEXT (1, &depth_stencil_buffer_id);
-      gdk_gl_context_label_object_printf (self->gl_context, GL_RENDERBUFFER, depth_stencil_buffer_id,
-                                          "%s buffer for %d", add_depth_buffer ? "Depth" : "Stencil", texture_id);
-    }
-  else
-    depth_stencil_buffer_id = 0;
-
-  glBindRenderbuffer (GL_RENDERBUFFER, depth_stencil_buffer_id);
-
-  if (add_depth_buffer || add_stencil_buffer)
-    {
-      if (add_stencil_buffer)
-        glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, t->width, t->height);
-      else
-        glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, t->width, t->height);
-
-      if (add_depth_buffer)
-        glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
-                                   GL_RENDERBUFFER, depth_stencil_buffer_id);
-
-      if (add_stencil_buffer)
-        glFramebufferRenderbufferEXT (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
-                                      GL_RENDERBUFFER, depth_stencil_buffer_id);
-  texture->fbo.depth_stencil_id = depth_stencil_buffer_id;
-    }
-#endif
-
-  texture->fbo.fbo_id = fbo_id;
-
-  g_assert_cmphex (glCheckFramebufferStatus (GL_FRAMEBUFFER), ==, GL_FRAMEBUFFER_COMPLETE);
-
-  glBindFramebuffer (GL_FRAMEBUFFER, self->default_fbo.fbo_id);
-
-  *out_texture_id = texture->texture_id;
-  *out_render_target_id = fbo_id;
-}
-
-/* Mark the texture permanent, meaning it won'e be reused by the GLDriver.
- * E.g. to store it in some other cache. */
-void
-gsk_gl_driver_mark_texture_permanent (GskGLDriver *self,
-                                      int          texture_id)
-{
-  Texture *t = gsk_gl_driver_get_texture (self, texture_id);
-
-  g_assert (t != NULL);
-
-  t->permanent = TRUE;
-}
-
-void
-gsk_gl_driver_bind_source_texture (GskGLDriver *self,
-                                   int          texture_id)
-{
-  Texture *t;
-
-  g_return_if_fail (GSK_IS_GL_DRIVER (self));
-  g_return_if_fail (self->in_frame);
-
-  t = gsk_gl_driver_get_texture (self, texture_id);
-  if (t == NULL)
-    {
-      g_critical ("No texture %d found.", texture_id);
-      return;
-    }
-
-  if (self->bound_source_texture != t)
-    {
-      glActiveTexture (GL_TEXTURE0);
-      glBindTexture (GL_TEXTURE_2D, t->texture_id);
-
-      self->bound_source_texture = t;
-    }
-}
-
-void
-gsk_gl_driver_destroy_texture (GskGLDriver *self,
-                               int          texture_id)
-{
-  g_return_if_fail (GSK_IS_GL_DRIVER (self));
-
-  g_hash_table_remove (self->textures, GINT_TO_POINTER (texture_id));
-}
-
-
-void
-gsk_gl_driver_init_texture_empty (GskGLDriver *self,
-                                  int          texture_id,
-                                  int          min_filter,
-                                  int          mag_filter)
-{
-  Texture *t;
-
-  g_return_if_fail (GSK_IS_GL_DRIVER (self));
-
-  t = gsk_gl_driver_get_texture (self, texture_id);
-  if (t == NULL)
-    {
-      g_critical ("No texture %d found.", texture_id);
-      return;
-    }
-
-  if (self->bound_source_texture != t)
-    {
-      g_critical ("You must bind the texture before initializing it.");
-      return;
-    }
-
-  t->min_filter = min_filter;
-  t->mag_filter = mag_filter;
-
-  gsk_gl_driver_set_texture_parameters (self, t->min_filter, t->mag_filter);
-
-  if (gdk_gl_context_get_use_es (self->gl_context))
-    glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, t->width, t->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-  else
-    glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, t->width, t->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
-
-  glBindTexture (GL_TEXTURE_2D, 0);
-}
-
-static gboolean
-filter_uses_mipmaps (int filter)
-{
-  return filter != GL_NEAREST && filter != GL_LINEAR;
-}
-
-void
-gsk_gl_driver_init_texture (GskGLDriver     *self,
-                            int              texture_id,
-                            GdkTexture      *texture,
-                            int              min_filter,
-                            int              mag_filter)
-{
-  Texture *t;
-
-  g_return_if_fail (GSK_IS_GL_DRIVER (self));
-
-  t = gsk_gl_driver_get_texture (self, texture_id);
-  if (t == NULL)
-    {
-      g_critical ("No texture %d found.", texture_id);
-      return;
-    }
-
-  if (self->bound_source_texture != t)
-    {
-      g_critical ("You must bind the texture before initializing it.");
-      return;
-    }
-
-  gsk_gl_driver_set_texture_parameters (self, min_filter, mag_filter);
-
-  upload_gdk_texture (texture, GL_TEXTURE_2D, 0, 0, t->width, t->height);
-
-#ifdef G_ENABLE_DEBUG
-  gsk_profiler_counter_inc (self->profiler, self->counters.surface_uploads);
-#endif
-
-  t->min_filter = min_filter;
-  t->mag_filter = mag_filter;
-
-  if (filter_uses_mipmaps (t->min_filter))
-    glGenerateMipmap (GL_TEXTURE_2D);
-}
diff --git a/gsk/gl/gskgldriverprivate.h b/gsk/gl/gskgldriverprivate.h
deleted file mode 100644 (file)
index 86c5dd9..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-#ifndef __GSK_GL_DRIVER_PRIVATE_H__
-#define __GSK_GL_DRIVER_PRIVATE_H__
-
-#include <cairo.h>
-#include <gdk/gdk.h>
-#include <graphene.h>
-
-G_BEGIN_DECLS
-
-#define GSK_TYPE_GL_DRIVER (gsk_gl_driver_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskGLDriver, gsk_gl_driver, GSK, GL_DRIVER, GObject)
-
-typedef struct {
-  float position[2];
-  float uv[2];
-} GskQuadVertex;
-
-typedef struct {
-  cairo_rectangle_int_t rect;
-  guint texture_id;
-} TextureSlice;
-
-typedef struct {
-  gpointer pointer;
-  float scale_x;
-  float scale_y;
-  int filter;
-  int pointer_is_child;
-  graphene_rect_t parent_rect; /* Only set if pointer_is_child */
-} GskTextureKey;
-
-GskGLDriver *   gsk_gl_driver_new                       (GdkGLContext    *context);
-GdkGLContext   *gsk_gl_driver_get_gl_context            (GskGLDriver     *driver);
-
-int             gsk_gl_driver_get_max_texture_size      (GskGLDriver     *driver);
-
-void            gsk_gl_driver_begin_frame               (GskGLDriver     *driver);
-void            gsk_gl_driver_end_frame                 (GskGLDriver     *driver);
-gboolean        gsk_gl_driver_in_frame                  (GskGLDriver     *driver);
-int             gsk_gl_driver_get_texture_for_texture   (GskGLDriver     *driver,
-                                                         GdkTexture      *texture,
-                                                         int              min_filter,
-                                                         int              mag_filter);
-int             gsk_gl_driver_get_texture_for_key       (GskGLDriver     *driver,
-                                                         GskTextureKey   *key);
-void            gsk_gl_driver_set_texture_for_key       (GskGLDriver     *driver,
-                                                         GskTextureKey   *key,
-                                                         int              texture_id);
-int             gsk_gl_driver_create_texture            (GskGLDriver     *driver,
-                                                         float            width,
-                                                         float            height);
-void            gsk_gl_driver_create_render_target      (GskGLDriver     *driver,
-                                                         int              width,
-                                                         int              height,
-                                                         int              min_filter,
-                                                         int              mag_filter,
-                                                         int             *out_texture_id,
-                                                         int             *out_render_target_id);
-void            gsk_gl_driver_mark_texture_permanent    (GskGLDriver     *self,
-                                                         int              texture_id);
-void            gsk_gl_driver_bind_source_texture       (GskGLDriver     *driver,
-                                                         int              texture_id);
-
-void            gsk_gl_driver_init_texture_empty        (GskGLDriver     *driver,
-                                                         int              texture_id,
-                                                         int              min_filter,
-                                                         int              max_filter);
-void            gsk_gl_driver_init_texture              (GskGLDriver     *driver,
-                                                         int              texture_id,
-                                                         GdkTexture      *texture,
-                                                         int              min_filter,
-                                                         int              mag_filter);
-
-void            gsk_gl_driver_destroy_texture           (GskGLDriver     *driver,
-                                                         int              texture_id);
-
-int             gsk_gl_driver_collect_textures          (GskGLDriver     *driver);
-void            gsk_gl_driver_slice_texture             (GskGLDriver     *self,
-                                                         GdkTexture      *texture,
-                                                         TextureSlice   **out_slices,
-                                                         guint           *out_n_slices);
-
-G_END_DECLS
-
-#endif /* __GSK_GL_DRIVER_PRIVATE_H__ */
diff --git a/gsk/gl/gskglglyphcache.c b/gsk/gl/gskglglyphcache.c
deleted file mode 100644 (file)
index 864c741..0000000
+++ /dev/null
@@ -1,397 +0,0 @@
-#include "config.h"
-
-#include "gskglglyphcacheprivate.h"
-#include "gskgldriverprivate.h"
-#include "gskdebugprivate.h"
-#include "gskprivate.h"
-#include "gskgltextureatlasprivate.h"
-
-#include "gdk/gdkglcontextprivate.h"
-#include "gdk/gdkmemorytextureprivate.h"
-
-#include <graphene.h>
-#include <cairo.h>
-#include <epoxy/gl.h>
-#include <string.h>
-
-/* Cache eviction strategy
- *
- * We mark glyphs as accessed every time we use them.
- * Every few frames, we mark glyphs that haven't been
- * accessed since the last check as old.
- *
- * We keep count of the pixels of each atlas that are
- * taken up by old data. When the fraction of old pixels
- * gets too high, we drop the atlas and all the items it
- * contained.
- *
- * Big glyphs are not stored in the atlas, they get their
- * own texture, but they are still cached.
- */
-
-#define MAX_FRAME_AGE (60)
-#define MAX_GLYPH_SIZE 128 /* Will get its own texture if bigger */
-
-static guint    glyph_cache_hash       (gconstpointer v);
-static gboolean glyph_cache_equal      (gconstpointer v1,
-                                        gconstpointer v2);
-static void     glyph_cache_key_free   (gpointer      v);
-static void     glyph_cache_value_free (gpointer      v);
-
-GskGLGlyphCache *
-gsk_gl_glyph_cache_new (GdkDisplay *display,
-                        GskGLTextureAtlases *atlases)
-{
-  GskGLGlyphCache *glyph_cache;
-
-  glyph_cache = g_new0 (GskGLGlyphCache, 1);
-
-  glyph_cache->display = display;
-  glyph_cache->hash_table = g_hash_table_new_full (glyph_cache_hash, glyph_cache_equal,
-                                                   glyph_cache_key_free, glyph_cache_value_free);
-
-  glyph_cache->atlases = gsk_gl_texture_atlases_ref (atlases);
-
-  glyph_cache->ref_count = 1;
-
-  return glyph_cache;
-}
-
-GskGLGlyphCache *
-gsk_gl_glyph_cache_ref (GskGLGlyphCache *self)
-{
-  self->ref_count++;
-
-  return self;
-}
-
-void
-gsk_gl_glyph_cache_unref (GskGLGlyphCache *self)
-{
-  g_assert (self->ref_count > 0);
-
-  if (self->ref_count == 1)
-    {
-      gsk_gl_texture_atlases_unref (self->atlases);
-      g_hash_table_unref (self->hash_table);
-      g_free (self);
-      return;
-    }
-
-  self->ref_count--;
-}
-
-static gboolean
-glyph_cache_equal (gconstpointer v1, gconstpointer v2)
-{
-  return memcmp (v1, v2, sizeof (CacheKeyData)) == 0;
-}
-
-static guint
-glyph_cache_hash (gconstpointer v)
-{
-  const GlyphCacheKey *key = v;
-
-  return key->hash;
-}
-
-static void
-glyph_cache_key_free (gpointer v)
-{
-  GlyphCacheKey *f = v;
-
-  g_object_unref (f->data.font);
-  g_free (f);
-}
-
-static void
-glyph_cache_value_free (gpointer v)
-{
-  g_free (v);
-}
-
-static gboolean
-render_glyph (GlyphCacheKey    *key,
-              GskGLCachedGlyph *value,
-              GskImageRegion   *region)
-{
-  cairo_surface_t *surface;
-  cairo_t *cr;
-  cairo_scaled_font_t *scaled_font;
-  PangoGlyphString glyph_string;
-  PangoGlyphInfo glyph_info;
-  int surface_width, surface_height;
-  int stride;
-  unsigned char *data;
-
-  scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)key->data.font);
-  if (G_UNLIKELY (!scaled_font || cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS))
-    {
-      g_warning ("Failed to get a font");
-      return FALSE;
-    }
-
-  surface_width = value->draw_width * key->data.scale / 1024;
-  surface_height = value->draw_height * key->data.scale / 1024;
-
-  stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, surface_width);
-  data = g_malloc0 (stride * surface_height);
-  surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32,
-                                                 surface_width, surface_height,
-                                                 stride);
-  cairo_surface_set_device_scale (surface, key->data.scale / 1024.0, key->data.scale / 1024.0);
-
-  cr = cairo_create (surface);
-
-  cairo_set_scaled_font (cr, scaled_font);
-  cairo_set_source_rgba (cr, 1, 1, 1, 1);
-
-  glyph_info.glyph = key->data.glyph;
-  glyph_info.geometry.width = value->draw_width * 1024;
-  if (glyph_info.glyph & PANGO_GLYPH_UNKNOWN_FLAG)
-    glyph_info.geometry.x_offset = 256 * key->data.xshift;
-  else
-    glyph_info.geometry.x_offset = 256 * key->data.xshift - value->draw_x * 1024;
-  glyph_info.geometry.y_offset = 256 * key->data.yshift - value->draw_y * 1024;
-
-  glyph_string.num_glyphs = 1;
-  glyph_string.glyphs = &glyph_info;
-
-  pango_cairo_show_glyph_string (cr, key->data.font, &glyph_string);
-  cairo_destroy (cr);
-
-  cairo_surface_flush (surface);
-
-  region->width = cairo_image_surface_get_width (surface);
-  region->height = cairo_image_surface_get_height (surface);
-  region->stride = cairo_image_surface_get_stride (surface);
-  region->data = data;
-  if (value->atlas)
-    {
-      region->x = (gsize)(value->tx * value->atlas->width);
-      region->y = (gsize)(value->ty * value->atlas->height);
-    }
-  else
-    {
-      region->x = 0;
-      region->y = 0;
-    }
-
-  cairo_surface_destroy (surface);
-
-  return TRUE;
-}
-
-static void
-upload_glyph (GlyphCacheKey    *key,
-              GskGLCachedGlyph *value)
-{
-  GskImageRegion r;
-  guchar *pixel_data;
-  guchar *free_data = NULL;
-  guint gl_format;
-  guint gl_type;
-
-  gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (),
-                                          "Uploading glyph %d",
-                                          key->data.glyph);
-
-  if (render_glyph (key, value, &r))
-    {
-      glPixelStorei (GL_UNPACK_ROW_LENGTH, r.stride / 4);
-      glBindTexture (GL_TEXTURE_2D, value->texture_id);
-
-      if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ()))
-        {
-          pixel_data = free_data = g_malloc (r.width * r.height * 4);
-          gdk_memory_convert (pixel_data, r.width * 4,
-                              GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
-                              r.data, r.width * 4,
-                              GDK_MEMORY_DEFAULT, r.width, r.height);
-          gl_format = GL_RGBA;
-          gl_type = GL_UNSIGNED_BYTE;
-        }
-      else
-        {
-          pixel_data = r.data;
-          gl_format = GL_BGRA;
-          gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
-        }
-
-      glTexSubImage2D (GL_TEXTURE_2D, 0, r.x, r.y, r.width, r.height,
-                       gl_format, gl_type, pixel_data);
-      glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
-      g_free (r.data);
-      g_free (free_data);
-    }
-
-  gdk_gl_context_pop_debug_group (gdk_gl_context_get_current ());
-}
-
-static void
-add_to_cache (GskGLGlyphCache  *self,
-              GlyphCacheKey    *key,
-              GskGLDriver      *driver,
-              GskGLCachedGlyph *value)
-{
-  const int width = value->draw_width * key->data.scale / 1024;
-  const int height = value->draw_height * key->data.scale / 1024;
-
-  if (width < MAX_GLYPH_SIZE && height < MAX_GLYPH_SIZE)
-    {
-      GskGLTextureAtlas *atlas = NULL;
-      int packed_x = 0;
-      int packed_y = 0;
-
-      gsk_gl_texture_atlases_pack (self->atlases, width + 2, height + 2, &atlas, &packed_x, &packed_y);
-
-      value->tx = (float)(packed_x + 1) / atlas->width;
-      value->ty = (float)(packed_y + 1) / atlas->height;
-      value->tw = (float)width / atlas->width;
-      value->th = (float)height / atlas->height;
-      value->used = TRUE;
-
-      value->atlas = atlas;
-      value->texture_id = atlas->texture_id;
-    }
-  else
-    {
-      value->atlas = NULL;
-      value->texture_id = gsk_gl_driver_create_texture (driver, width, height);
-      gsk_gl_driver_mark_texture_permanent (driver, value->texture_id);
-
-      gsk_gl_driver_bind_source_texture (driver, value->texture_id);
-      gsk_gl_driver_init_texture_empty (driver, value->texture_id, GL_LINEAR, GL_LINEAR);
-
-      value->tx = 0.0f;
-      value->ty = 0.0f;
-      value->tw = 1.0f;
-      value->th = 1.0f;
-    }
-
-  upload_glyph (key, value);
-}
-
-void
-gsk_gl_glyph_cache_lookup_or_add (GskGLGlyphCache         *cache,
-                                  GlyphCacheKey           *lookup,
-                                  GskGLDriver             *driver,
-                                  const GskGLCachedGlyph **cached_glyph_out)
-{
-  GskGLCachedGlyph *value;
-
-  value = g_hash_table_lookup (cache->hash_table, lookup);
-
-  if (value)
-    {
-      if (value->atlas && !value->used)
-        {
-          gsk_gl_texture_atlas_mark_used (value->atlas, value->draw_width, value->draw_height);
-          value->used = TRUE;
-        }
-      value->accessed = TRUE;
-
-      *cached_glyph_out = value;
-      return;
-    }
-
-  {
-    GlyphCacheKey *key;
-    PangoRectangle ink_rect;
-
-    pango_font_get_glyph_extents (lookup->data.font, lookup->data.glyph, &ink_rect, NULL);
-    pango_extents_to_pixels (&ink_rect, NULL);
-    if (lookup->data.xshift != 0)
-      ink_rect.width += 1;
-    if (lookup->data.yshift != 0)
-      ink_rect.height += 1;
-
-    value = g_new0 (GskGLCachedGlyph, 1);
-
-    value->draw_x = ink_rect.x;
-    value->draw_y = ink_rect.y;
-    value->draw_width = ink_rect.width;
-    value->draw_height = ink_rect.height;
-    value->accessed = TRUE;
-    value->atlas = NULL; /* For now */
-
-    key = g_new0 (GlyphCacheKey, 1);
-
-    key->data.font = g_object_ref (lookup->data.font);
-    key->data.glyph = lookup->data.glyph;
-    key->data.xshift = lookup->data.xshift;
-    key->data.yshift = lookup->data.yshift;
-    key->data.scale = lookup->data.scale;
-    key->hash = lookup->hash;
-
-    if (key->data.scale > 0 &&
-        value->draw_width * key->data.scale / 1024 > 0 &&
-        value->draw_height * key->data.scale / 1024 > 0)
-      add_to_cache (cache, key, driver, value);
-
-    *cached_glyph_out = value;
-    g_hash_table_insert (cache->hash_table, key, value);
-  }
-}
-
-void
-gsk_gl_glyph_cache_begin_frame (GskGLGlyphCache *self,
-                                GskGLDriver     *driver,
-                                GPtrArray       *removed_atlases)
-{
-  GHashTableIter iter;
-  GlyphCacheKey *key;
-  GskGLCachedGlyph *value;
-  guint dropped = 0;
-
-  self->timestamp++;
-
-  if (removed_atlases->len > 0)
-    {
-      g_hash_table_iter_init (&iter, self->hash_table);
-      while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value))
-        {
-          if (g_ptr_array_find (removed_atlases, value->atlas, NULL))
-            {
-              g_hash_table_iter_remove (&iter);
-              dropped++;
-            }
-        }
-    }
-
-  if (self->timestamp % MAX_FRAME_AGE == 30)
-    {
-      g_hash_table_iter_init (&iter, self->hash_table);
-      while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value))
-        {
-          if (!value->accessed)
-            {
-              if (value->atlas)
-                {
-                  if (value->used)
-                    {
-                      gsk_gl_texture_atlas_mark_unused (value->atlas, value->draw_width, value->draw_height);
-                      value->used = FALSE;
-                    }
-                }
-              else
-                {
-                  gsk_gl_driver_destroy_texture (driver, value->texture_id);
-                  g_hash_table_iter_remove (&iter);
-
-                  /* Sadly, if we drop an atlas-less cached glyph, we
-                   * have to treat it like a dropped atlas and purge
-                   * text node render data.
-                   */
-                  dropped++;
-                }
-            }
-          else
-            value->accessed = FALSE;
-       }
-
-      GSK_NOTE(GLYPH_CACHE, g_message ("%d glyphs cached", g_hash_table_size (self->hash_table)));
-    }
-
-  GSK_NOTE(GLYPH_CACHE, if (dropped > 0) g_message ("Dropped %d glyphs", dropped));
-}
diff --git a/gsk/gl/gskglglyphcacheprivate.h b/gsk/gl/gskglglyphcacheprivate.h
deleted file mode 100644 (file)
index d66b251..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-#ifndef __GSK_GL_GLYPH_CACHE_PRIVATE_H__
-#define __GSK_GL_GLYPH_CACHE_PRIVATE_H__
-
-#include "gskgldriverprivate.h"
-#include "gskglimageprivate.h"
-#include "gskgltextureatlasprivate.h"
-#include <pango/pango.h>
-#include <gdk/gdk.h>
-
-typedef struct
-{
-  int ref_count;
-
-  GdkDisplay *display;
-  GHashTable *hash_table;
-  GskGLTextureAtlases *atlases;
-
-  int timestamp;
-} GskGLGlyphCache;
-
-struct _CacheKeyData
-{
-  PangoFont *font;
-  PangoGlyph glyph;
-  guint xshift : 3;
-  guint yshift : 3;
-  guint scale  : 26; /* times 1024 */
-};
-
-typedef struct _CacheKeyData CacheKeyData;
-
-struct _GlyphCacheKey
-{
-  CacheKeyData data;
-  guint hash;
-};
-
-typedef struct _GlyphCacheKey GlyphCacheKey;
-
-#define PHASE(x) ((int)(floor (4 * (x + 0.125)) - 4 * floor (x + 0.125)))
-
-static inline void
-glyph_cache_key_set_glyph_and_shift (GlyphCacheKey *key,
-                                     PangoGlyph glyph,
-                                     float x,
-                                     float y)
-{
-  key->data.glyph = glyph;
-  key->data.xshift = PHASE (x);
-  key->data.yshift = PHASE (y);
-  key->hash = GPOINTER_TO_UINT (key->data.font) ^
-              key->data.glyph ^
-              (key->data.xshift << 24) ^
-              (key->data.yshift << 26) ^
-              key->data.scale;
-}
-
-typedef struct _GskGLCachedGlyph GskGLCachedGlyph;
-
-struct _GskGLCachedGlyph
-{
-  GskGLTextureAtlas *atlas;
-  guint texture_id;
-
-  float tx;
-  float ty;
-  float tw;
-  float th;
-
-  int draw_x;
-  int draw_y;
-  int draw_width;
-  int draw_height;
-
-  guint accessed : 1; /* accessed since last check */
-  guint used     : 1; /* accounted as used in the atlas */
-};
-
-
-GskGLGlyphCache *        gsk_gl_glyph_cache_new             (GdkDisplay *display,
-                                                             GskGLTextureAtlases *atlases);
-GskGLGlyphCache *        gsk_gl_glyph_cache_ref             (GskGLGlyphCache *self);
-void                     gsk_gl_glyph_cache_unref           (GskGLGlyphCache        *self);
-void                     gsk_gl_glyph_cache_begin_frame     (GskGLGlyphCache        *self,
-                                                             GskGLDriver            *driver,
-                                                             GPtrArray              *removed_atlases);
-void                     gsk_gl_glyph_cache_lookup_or_add   (GskGLGlyphCache        *self,
-                                                             GlyphCacheKey          *lookup,
-                                                             GskGLDriver            *driver,
-                                                             const GskGLCachedGlyph **cached_glyph_out);
-
-#endif
diff --git a/gsk/gl/gskgliconcache.c b/gsk/gl/gskgliconcache.c
deleted file mode 100644 (file)
index 4bbbdbb..0000000
+++ /dev/null
@@ -1,275 +0,0 @@
-#include "gskgliconcacheprivate.h"
-#include "gskgltextureatlasprivate.h"
-#include "gdk/gdktextureprivate.h"
-#include "gdk/gdkmemorytextureprivate.h"
-#include "gdk/gdkglcontextprivate.h"
-
-#include <epoxy/gl.h>
-
-#define MAX_FRAME_AGE 60
-
-static void
-icon_data_free (gpointer p)
-{
-  g_object_unref (((IconData *)p)->source_texture);
-  g_free (p);
-}
-
-GskGLIconCache *
-gsk_gl_icon_cache_new (GdkDisplay *display,
-                       GskGLTextureAtlases *atlases)
-{
-  GskGLIconCache *self;
-
-  self = g_new0 (GskGLIconCache, 1);
-
-  self->display = display;
-  self->icons = g_hash_table_new_full (NULL, NULL, NULL, icon_data_free);
-  self->atlases = gsk_gl_texture_atlases_ref (atlases);
-  self->ref_count = 1;
-
-  return self;
-}
-
-GskGLIconCache *
-gsk_gl_icon_cache_ref (GskGLIconCache *self)
-{
-  self->ref_count++;
-
-  return self;
-}
-
-void
-gsk_gl_icon_cache_unref (GskGLIconCache *self)
-{
-  g_assert (self->ref_count > 0);
-
-  if (self->ref_count == 1)
-    {
-      gsk_gl_texture_atlases_unref (self->atlases);
-      g_hash_table_unref (self->icons);
-      g_free (self);
-      return;
-    }
-
-  self->ref_count--;
-}
-
-void
-gsk_gl_icon_cache_begin_frame (GskGLIconCache *self,
-                               GPtrArray      *removed_atlases)
-{
-  GHashTableIter iter;
-  GdkTexture *texture;
-  IconData *icon_data;
-
-  self->timestamp++;
-
-  /* Drop icons on removed atlases */
-  if (removed_atlases->len > 0)
-    {
-      guint dropped = 0;
-
-      g_hash_table_iter_init (&iter, self->icons);
-      while (g_hash_table_iter_next (&iter, (gpointer *)&texture, (gpointer *)&icon_data))
-        {
-          if (g_ptr_array_find (removed_atlases, icon_data->atlas, NULL))
-            {
-              g_hash_table_iter_remove (&iter);
-              dropped++;
-            }
-        }
-
-      GSK_NOTE(GLYPH_CACHE, if (dropped > 0) g_message ("Dropped %d icons", dropped));
-    }
-
-  if (self->timestamp % MAX_FRAME_AGE == 0)
-    {
-      g_hash_table_iter_init (&iter, self->icons);
-      while (g_hash_table_iter_next (&iter, (gpointer *)&texture, (gpointer *)&icon_data))
-        {
-          if (!icon_data->accessed)
-            {
-              if (icon_data->used)
-                { 
-                  const int width = icon_data->source_texture->width;
-                  const int height = icon_data->source_texture->height;
-                  gsk_gl_texture_atlas_mark_unused (icon_data->atlas, width + 2, height + 2);
-                  icon_data->used = FALSE;
-                }
-            }
-
-          icon_data->accessed = FALSE;
-        }
-
-      GSK_NOTE(GLYPH_CACHE, g_message ("%d icons cached", g_hash_table_size (self->icons)));
-    }
-}
-
-void
-gsk_gl_icon_cache_lookup_or_add (GskGLIconCache  *self,
-                                 GdkTexture      *texture,
-                                 const IconData **out_icon_data)
-{
-  IconData *icon_data = g_hash_table_lookup (self->icons, texture);
-
-  if (icon_data)
-    {
-      if (!icon_data->used)
-        {
-          gsk_gl_texture_atlas_mark_used (icon_data->atlas, texture->width + 2, texture->height + 2);
-          icon_data->used = TRUE;
-        }
-      icon_data->accessed = TRUE;
-
-      *out_icon_data = icon_data;
-      return;
-    }
-
-  /* texture not on any atlas yet. Find a suitable one. */
-  {
-    const int width = texture->width;
-    const int height = texture->height;
-    GskGLTextureAtlas *atlas = NULL;
-    int packed_x = 0;
-    int packed_y = 0;
-    cairo_surface_t *surface;
-    unsigned char *surface_data;
-    unsigned char *pixel_data;
-    guchar *free_data = NULL;
-    guint gl_format;
-    guint gl_type;
-
-    gsk_gl_texture_atlases_pack (self->atlases, width + 2, height + 2, &atlas, &packed_x, &packed_y);
-
-    icon_data = g_new0 (IconData, 1);
-    icon_data->atlas = atlas;
-    icon_data->accessed = TRUE;
-    icon_data->used = TRUE;
-    icon_data->texture_id = atlas->texture_id;
-    icon_data->source_texture = g_object_ref (texture);
-    icon_data->x = (float)(packed_x + 1) / atlas->width;
-    icon_data->y = (float)(packed_y + 1) / atlas->width;
-    icon_data->x2 = icon_data->x + (float)width / atlas->width;
-    icon_data->y2 = icon_data->y + (float)height / atlas->height;
-
-    g_hash_table_insert (self->icons, texture, icon_data);
-
-    /* actually upload the texture */
-    surface = gdk_texture_download_surface (texture);
-    surface_data = cairo_image_surface_get_data (surface);
-    gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (),
-                                            "Uploading texture");
-
-    if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ()))
-      {
-        pixel_data = free_data = g_malloc (width * height * 4);
-        gdk_memory_convert (pixel_data, width * 4,
-                            GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
-                            surface_data, cairo_image_surface_get_stride (surface),
-                            GDK_MEMORY_DEFAULT, width, height);
-        gl_format = GL_RGBA;
-        gl_type = GL_UNSIGNED_BYTE;
-      }
-    else
-      {
-        pixel_data = surface_data;
-        gl_format = GL_BGRA;
-        gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
-      }
-
-    glBindTexture (GL_TEXTURE_2D, atlas->texture_id);
-
-    glTexSubImage2D (GL_TEXTURE_2D, 0,
-                     packed_x + 1, packed_y + 1,
-                     width, height,
-                     gl_format, gl_type,
-                     pixel_data);
-    /* Padding top */
-    glTexSubImage2D (GL_TEXTURE_2D, 0,
-                     packed_x + 1, packed_y,
-                     width, 1,
-                     gl_format, gl_type,
-                     pixel_data);
-    /* Padding left */
-    glTexSubImage2D (GL_TEXTURE_2D, 0,
-                     packed_x, packed_y + 1,
-                     1, height,
-                     gl_format, gl_type,
-                     pixel_data);
-    /* Padding top left */
-    glTexSubImage2D (GL_TEXTURE_2D, 0,
-                     packed_x, packed_y,
-                     1, 1,
-                     gl_format, gl_type,
-                     pixel_data);
-
-    /* Padding right */
-    glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
-    glPixelStorei (GL_UNPACK_SKIP_PIXELS, width - 1);
-    glTexSubImage2D (GL_TEXTURE_2D, 0,
-                     packed_x + width + 1, packed_y + 1,
-                     1, height,
-                     gl_format, gl_type,
-                     pixel_data);
-    /* Padding top right */
-    glTexSubImage2D (GL_TEXTURE_2D, 0,
-                     packed_x + width + 1, packed_y,
-                     1, 1,
-                     gl_format, gl_type,
-                     pixel_data);
-    /* Padding bottom */
-    glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
-    glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
-    glPixelStorei (GL_UNPACK_SKIP_ROWS, height - 1);
-    glTexSubImage2D (GL_TEXTURE_2D, 0,
-                     packed_x + 1, packed_y + 1 + height,
-                     width, 1,
-                     gl_format, gl_type,
-                     pixel_data);
-    /* Padding bottom left */
-    glTexSubImage2D (GL_TEXTURE_2D, 0,
-                     packed_x, packed_y + 1 + height,
-                     1, 1,
-                     gl_format, gl_type,
-                     pixel_data);
-    /* Padding bottom right */
-    glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
-    glPixelStorei (GL_UNPACK_SKIP_PIXELS, width - 1);
-    glTexSubImage2D (GL_TEXTURE_2D, 0,
-                     packed_x + 1 + width, packed_y + 1 + height,
-                     1, 1,
-                     gl_format, gl_type,
-                     pixel_data);
-    /* Reset this */
-    glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
-    glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
-    glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
-
-    gdk_gl_context_pop_debug_group (gdk_gl_context_get_current ());
-
-    *out_icon_data = icon_data;
-
-    cairo_surface_destroy (surface);
-    g_free (free_data);
-
-#if 0
-    {
-      static int k;
-      const int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, atlas->width);
-      guchar *data = g_malloc (atlas->height * stride);
-      cairo_surface_t *s;
-      char *filename = g_strdup_printf ("atlas_%u_%d.png", atlas->texture_id, k++);
-
-      glBindTexture (GL_TEXTURE_2D, atlas->texture_id);
-      glGetTexImage (GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, data);
-      s = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, atlas->width, atlas->height, stride);
-      cairo_surface_write_to_png (s, filename);
-
-      cairo_surface_destroy (s);
-      g_free (data);
-      g_free (filename);
-    }
-#endif
-  }
-}
diff --git a/gsk/gl/gskgliconcacheprivate.h b/gsk/gl/gskgliconcacheprivate.h
deleted file mode 100644 (file)
index e076278..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef __GSK_GL_ICON_CACHE_PRIVATE_H__
-#define __GSK_GL_ICON_CACHE_PRIVATE_H__
-
-#include "gskgldriverprivate.h"
-#include "gskglimageprivate.h"
-#include "gskrendererprivate.h"
-#include "gskgltextureatlasprivate.h"
-#include <pango/pango.h>
-#include <gdk/gdk.h>
-
-typedef struct
-{
-  int ref_count;
-
-  GdkDisplay *display;
-  GskGLDriver *gl_driver;
-
-  GskGLTextureAtlases *atlases;
-  GHashTable *icons; /* GdkTexture -> IconData */
-
-  int timestamp;
-} GskGLIconCache;
-
-typedef struct
-{
-  float x, y, x2, y2;
-  GskGLTextureAtlas *atlas;
-  guint used     : 1;
-  guint accessed : 1;
-  int texture_id;
-  GdkTexture *source_texture;
-} IconData;
-
-GskGLIconCache * gsk_gl_icon_cache_new            (GdkDisplay *display,
-                                                   GskGLTextureAtlases *atlases);
-GskGLIconCache * gsk_gl_icon_cache_ref            (GskGLIconCache        *self);
-void             gsk_gl_icon_cache_unref          (GskGLIconCache        *self);
-void             gsk_gl_icon_cache_begin_frame    (GskGLIconCache        *self,
-                                                   GPtrArray             *removed_atlases);
-void             gsk_gl_icon_cache_lookup_or_add  (GskGLIconCache        *self,
-                                                   GdkTexture            *texture,
-                                                   const IconData       **out_icon_data);
-
-#endif
diff --git a/gsk/gl/gskglimage.c b/gsk/gl/gskglimage.c
deleted file mode 100644 (file)
index 71d7bce..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-
-#include "gskglimageprivate.h"
-#include <epoxy/gl.h>
-
-void
-gsk_gl_image_create (GskGLImage  *self,
-                     GskGLDriver *gl_driver,
-                     int          width,
-                     int          height,
-                     int          min_filter,
-                     int          mag_filter)
-{
-  self->texture_id = gsk_gl_driver_create_texture (gl_driver, width, height);
-  self->width = width;
-  self->height = height;
-
-  gsk_gl_driver_bind_source_texture (gl_driver, self->texture_id);
-  gsk_gl_driver_init_texture_empty (gl_driver, self->texture_id, min_filter, mag_filter);
-  gsk_gl_driver_mark_texture_permanent (gl_driver, self->texture_id);
-}
-
-void
-gsk_gl_image_destroy (GskGLImage  *self,
-                      GskGLDriver *gl_driver)
-{
-  gsk_gl_driver_destroy_texture (gl_driver, self->texture_id);
-  self->texture_id = 0;
-}
-
-void
-gsk_gl_image_write_to_png (const GskGLImage *self,
-                           GskGLDriver      *gl_driver,
-                           const char       *filename)
-{
-  int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, self->width);
-  guchar *data = g_malloc (self->height * stride);
-  cairo_surface_t *s;
-
-  gsk_gl_driver_bind_source_texture (gl_driver, self->texture_id);
-  glGetTexImage (GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data);
-  s = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, self->width, self->height, stride);
-  cairo_surface_write_to_png (s, filename);
-
-  cairo_surface_destroy (s);
-  g_free (data);
-}
-
-void
-gsk_gl_image_upload_region (GskGLImage           *self,
-                            GskGLDriver          *gl_driver,
-                            const GskImageRegion *region)
-{
-  gsk_gl_driver_bind_source_texture (gl_driver, self->texture_id);
-  glBindTexture (GL_TEXTURE_2D, self->texture_id);
-
-  glTexSubImage2D (GL_TEXTURE_2D, 0, region->x, region->y, region->width, region->height,
-                   GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, region->data);
-
-#ifdef G_ENABLE_DEBUG
-  /*gsk_gl_driver_bind_source_texture (gl_driver, self->texture_id);*/
-  /*gsk_gl_image_dump (self, gl_driver, "/home/baedert/atlases/test_dump.png");*/
-#endif
-}
-
diff --git a/gsk/gl/gskglimageprivate.h b/gsk/gl/gskglimageprivate.h
deleted file mode 100644 (file)
index 3d70672..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef __GSK_GL_IMAGE_H__
-#define __GSK_GL_IMAGE_H__
-
-#include "gskgldriverprivate.h"
-#include <cairo.h>
-
-typedef struct
-{
-  guint texture_id;
-  int width;
-  int height;
-} GskGLImage;
-
-typedef struct
-{
-  guchar *data;
-  gsize width;
-  gsize height;
-  gsize stride;
-  gsize x;
-  gsize y;
-} GskImageRegion;
-
-void gsk_gl_image_create         (GskGLImage           *self,
-                                  GskGLDriver          *gl_driver,
-                                  int                   width,
-                                  int                   height,
-                                  int                   min_filter,
-                                  int                   mag_filter);
-void gsk_gl_image_destroy        (GskGLImage           *self,
-                                  GskGLDriver          *gl_driver);
-void gsk_gl_image_write_to_png   (const GskGLImage     *self,
-                                  GskGLDriver          *gl_driver,
-                                  const char           *filename);
-void gsk_gl_image_upload_region  (GskGLImage           *self,
-                                  GskGLDriver          *gl_driver,
-                                  const GskImageRegion *region);
-
-
-#endif
-
diff --git a/gsk/gl/gskglnodesample.c b/gsk/gl/gskglnodesample.c
deleted file mode 100644 (file)
index cf1afa5..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-
-#include <glib/gprintf.h>
-#include "gskglnodesampleprivate.h"
-#include "gskrendernodeprivate.h"
-
-void
-node_sample_init (NodeSample *self)
-{
-  memset (self->nodes, 0, sizeof (self->nodes));
-  self->count = 0;
-}
-
-void
-node_sample_reset (NodeSample *self)
-{
-  node_sample_init (self);
-}
-
-void
-node_sample_add (NodeSample    *self,
-                 GskRenderNode *node)
-{
-  const guint node_type = gsk_render_node_get_node_type (node);
-
-  g_assert (node_type <= N_NODE_TYPES);
-
-  if (self->nodes[node_type].class_name == NULL)
-    self->nodes[node_type].class_name = g_type_name_from_instance ((GTypeInstance *) node); 
-
-  self->nodes[node_type].count ++;
-  self->count ++;
-}
-
-void
-node_sample_print (const NodeSample *self,
-                   const char       *prefix)
-{
-  guint i;
-
-  g_printf ("%s:\n", prefix);
-
-  for (i = 0; i < N_NODE_TYPES; i ++)
-    {
-      if (self->nodes[i].count > 0)
-        {
-          double p = (double)self->nodes[i].count / (double)self->count;
-
-          g_printf ("%s: %u (%.2f%%)\n", self->nodes[i].class_name, self->nodes[i].count, p * 100.0);
-        }
-    }
-}
diff --git a/gsk/gl/gskglnodesampleprivate.h b/gsk/gl/gskglnodesampleprivate.h
deleted file mode 100644 (file)
index a1d09a0..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-
-#ifndef __GSK_GL_NODE_SAMPLE_PRIVATE_H__
-#define __GSK_GL_NODE_SAMPLE_PRIVATE_H__
-
-#include <glib.h>
-#include "gskenums.h"
-#include "gskrendernode.h"
-
-/* TODO: We have no other way for this...? */
-#define N_NODE_TYPES (GSK_DEBUG_NODE + 1)
-
-typedef struct
-{
-  struct {
-    const char *class_name;
-    guint count;
-  } nodes[N_NODE_TYPES];
-  guint count;
-} NodeSample;
-
-void node_sample_init  (NodeSample       *self);
-void node_sample_reset (NodeSample       *self);
-void node_sample_add   (NodeSample       *self,
-                        GskRenderNode    *node);
-void node_sample_print (const NodeSample *self,
-                        const char       *prefix);
-
-#endif
diff --git a/gsk/gl/gskglprofiler.c b/gsk/gl/gskglprofiler.c
deleted file mode 100644 (file)
index 9b834e5..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-#include "config.h"
-
-#include "gskglprofilerprivate.h"
-
-#include <epoxy/gl.h>
-
-#define N_QUERIES       4
-
-struct _GskGLProfiler
-{
-  GObject parent_instance;
-
-  GdkGLContext *gl_context;
-
-  /* Creating GL queries is kind of expensive, so we pay the
-   * price upfront and create a circular buffer of queries
-   */
-  GLuint gl_queries[N_QUERIES];
-  GLuint active_query;
-
-  gboolean has_queries : 1;
-  gboolean has_timer : 1;
-  gboolean first_frame : 1;
-};
-
-enum {
-  PROP_GL_CONTEXT = 1,
-
-  N_PROPERTIES
-};
-
-static GParamSpec *gsk_gl_profiler_properties[N_PROPERTIES];
-
-G_DEFINE_TYPE (GskGLProfiler, gsk_gl_profiler, G_TYPE_OBJECT)
-
-static void
-gsk_gl_profiler_finalize (GObject *gobject)
-{
-  GskGLProfiler *self = GSK_GL_PROFILER (gobject);
-
-  if (self->has_queries)
-    glDeleteQueries (N_QUERIES, self->gl_queries);
-
-  g_clear_object (&self->gl_context);
-
-  G_OBJECT_CLASS (gsk_gl_profiler_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_gl_profiler_set_property (GObject      *gobject,
-                              guint         prop_id,
-                              const GValue *value,
-                              GParamSpec   *pspec)
-{
-  GskGLProfiler *self = GSK_GL_PROFILER (gobject);
-
-  switch (prop_id)
-    {
-    case PROP_GL_CONTEXT:
-      self->gl_context = g_value_dup_object (value);
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
-    }
-}
-
-static void
-gsk_gl_profiler_get_property (GObject    *gobject,
-                              guint       prop_id,
-                              GValue     *value,
-                              GParamSpec *pspec)
-{
-  GskGLProfiler *self = GSK_GL_PROFILER (gobject);
-
-  switch (prop_id)
-    {
-    case PROP_GL_CONTEXT:
-      g_value_set_object (value, self->gl_context);
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
-    }
-}
-
-static void
-gsk_gl_profiler_class_init (GskGLProfilerClass *klass)
-{
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
-  gobject_class->set_property = gsk_gl_profiler_set_property;
-  gobject_class->get_property = gsk_gl_profiler_get_property;
-  gobject_class->finalize = gsk_gl_profiler_finalize;
-
-  gsk_gl_profiler_properties[PROP_GL_CONTEXT] =
-    g_param_spec_object ("gl-context",
-                         "GL Context",
-                         "The GdkGLContext used by the GL profiler",
-                         GDK_TYPE_GL_CONTEXT,
-                         G_PARAM_READWRITE |
-                         G_PARAM_CONSTRUCT_ONLY |
-                         G_PARAM_STATIC_STRINGS);
-
-  g_object_class_install_properties (gobject_class, N_PROPERTIES, gsk_gl_profiler_properties);
-}
-
-static void
-gsk_gl_profiler_init (GskGLProfiler *self)
-{
-  self->has_queries = epoxy_is_desktop_gl();
-  self->has_timer = epoxy_is_desktop_gl() && (epoxy_gl_version () >= 33 || epoxy_has_gl_extension ("GL_ARB_timer_query"));
-
-  if (!self->has_queries)
-    return;
-
-  glGenQueries (N_QUERIES, self->gl_queries);
-  self->first_frame = TRUE;
-}
-
-GskGLProfiler *
-gsk_gl_profiler_new (GdkGLContext *context)
-{
-  g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
-
-  return g_object_new (GSK_TYPE_GL_PROFILER, "gl-context", context, NULL);
-}
-
-void
-gsk_gl_profiler_begin_gpu_region (GskGLProfiler *profiler)
-{
-  GLuint query_id;
-
-  g_return_if_fail (GSK_IS_GL_PROFILER (profiler));
-
-  if (!profiler->has_timer || !profiler->has_queries)
-    return;
-
-  query_id = profiler->gl_queries[profiler->active_query];
-  glBeginQuery (GL_TIME_ELAPSED, query_id);
-}
-
-guint64
-gsk_gl_profiler_end_gpu_region (GskGLProfiler *profiler)
-{
-  GLuint last_query_id;
-  GLint res;
-  GLuint64 elapsed;
-
-  g_return_val_if_fail (GSK_IS_GL_PROFILER (profiler), 0);
-
-  if (!profiler->has_timer || !profiler->has_queries)
-    return 0;
-
-  glEndQuery (GL_TIME_ELAPSED);
-
-  if (profiler->active_query == 0)
-    last_query_id = N_QUERIES - 1;
-  else
-    last_query_id = profiler->active_query - 1;
-
-  /* Advance iterator */
-  profiler->active_query += 1;
-  if (profiler->active_query == N_QUERIES)
-    profiler->active_query = 0;
-
-  /* If this is the first frame we already have a result */
-  if (profiler->first_frame)
-    {
-      profiler->first_frame = FALSE;
-      return 0;
-    }
-
-  glGetQueryObjectiv (profiler->gl_queries[last_query_id], GL_QUERY_RESULT_AVAILABLE, &res);
-  if (res == 1)
-    glGetQueryObjectui64v (profiler->gl_queries[last_query_id], GL_QUERY_RESULT, &elapsed);
-  else
-    elapsed = 0;
-
-  return elapsed / 1000; /* Convert to usec to match other profiler APIs */
-}
diff --git a/gsk/gl/gskglprofilerprivate.h b/gsk/gl/gskglprofilerprivate.h
deleted file mode 100644 (file)
index 5b2a24b..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef __GSK_GL_PROFILER_PRIVATE_H__
-#define __GSK_GL_PROFILER_PRIVATE_H__
-
-#include <gsk/gsktypes.h>
-
-G_BEGIN_DECLS
-
-#define GSK_TYPE_GL_PROFILER (gsk_gl_profiler_get_type ())
-G_DECLARE_FINAL_TYPE (GskGLProfiler, gsk_gl_profiler, GSK, GL_PROFILER, GObject)
-
-GskGLProfiler * gsk_gl_profiler_new                     (GdkGLContext  *context);
-
-void            gsk_gl_profiler_begin_gpu_region        (GskGLProfiler *profiler);
-guint64         gsk_gl_profiler_end_gpu_region          (GskGLProfiler *profiler);
-
-G_END_DECLS
-
-#endif /* __GSK_GL_PROFILER_PRIVATE_H__ */
diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c
deleted file mode 100644 (file)
index a801f55..0000000
+++ /dev/null
@@ -1,4559 +0,0 @@
-#include "config.h"
-
-#include "gskglrendererprivate.h"
-
-#include "gskdebugprivate.h"
-#include "gskenums.h"
-#include "gskgldriverprivate.h"
-#include "gskglprofilerprivate.h"
-#include "gskprofilerprivate.h"
-#include "gskrendererprivate.h"
-#include "gskrendernodeprivate.h"
-#include "gsktransformprivate.h"
-#include "gskglshaderbuilderprivate.h"
-#include "gskglglyphcacheprivate.h"
-#include "gskgliconcacheprivate.h"
-#include "gskglrenderopsprivate.h"
-#include "gskcairoblurprivate.h"
-#include "gskglshadowcacheprivate.h"
-#include "gskglnodesampleprivate.h"
-#include "gsktransform.h"
-#include "glutilsprivate.h"
-#include "gskglshaderprivate.h"
-
-#include "gskprivate.h"
-
-#include "gdk/gdkgltextureprivate.h"
-#include "gdk/gdkglcontextprivate.h"
-#include "gdk/gdkprofilerprivate.h"
-#include "gdk/gdkrgbaprivate.h"
-
-#include <epoxy/gl.h>
-
-#define SHADER_VERSION_GLES             100
-#define SHADER_VERSION_GL2_LEGACY       110
-#define SHADER_VERSION_GL3_LEGACY       130
-#define SHADER_VERSION_GL3              150
-
-#define ORTHO_NEAR_PLANE        -10000
-#define ORTHO_FAR_PLANE          10000
-
-#define DEBUG_OPS          0
-
-#define SHADOW_EXTRA_SIZE  4
-
-#if DEBUG_OPS
-#define OP_PRINT(format, ...) g_print(format, ## __VA_ARGS__)
-#else
-#define OP_PRINT(format, ...)
-#endif
-
-#define INIT_PROGRAM_UNIFORM_LOCATION(program_name, uniform_basename) \
-              G_STMT_START{\
-                programs->program_name ## _program.program_name.uniform_basename ## _location = \
-                              glGetUniformLocation(programs->program_name ## _program.id, "u_" #uniform_basename);\
-                if (programs->program_name ## _program.program_name.uniform_basename ## _location == -1) \
-                  { \
-                    g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_LINK_FAILED, \
-                                 "Failed to find variable \"u_%s\" in shader program \"%s\"", #uniform_basename, #program_name); \
-                    g_clear_pointer (&programs, gsk_gl_renderer_programs_unref); \
-                    goto out; \
-                  } \
-              }G_STMT_END
-
-#define INIT_COMMON_UNIFORM_LOCATION(program_ptr, uniform_basename) \
-              G_STMT_START{\
-                program_ptr->uniform_basename ## _location =  \
-                              glGetUniformLocation(program_ptr->id, "u_" #uniform_basename);\
-              }G_STMT_END
-
-static Program *gsk_gl_renderer_lookup_custom_program (GskGLRenderer  *self,
-                                                       GskGLShader *shader);
-static Program *gsk_gl_renderer_create_custom_program (GskGLRenderer  *self,
-                                                       GskGLShader *shader);
-
-typedef enum
-{
-  FORCE_OFFSCREEN  = 1 << 0,
-  RESET_CLIP       = 1 << 1,
-  DUMP_FRAMEBUFFER = 1 << 3,
-  NO_CACHE_PLZ     = 1 << 5,
-  LINEAR_FILTER    = 1 << 6,
-} OffscreenFlags;
-
-static inline void
-init_full_texture_region (TextureRegion *r,
-                          int            texture_id)
-{
-  r->texture_id = texture_id;
-  r->x = 0;
-  r->y = 0;
-  r->x2 = 1;
-  r->y2 = 1;
-}
-
-static void G_GNUC_UNUSED
-print_render_node_tree (GskRenderNode *root, int level)
-{
-#define INDENT 4
-  const guint type = gsk_render_node_get_node_type (root);
-  guint i;
-
-  switch (type)
-    {
-      case GSK_CONTAINER_NODE:
-        g_print ("%*s Container\n", level * INDENT, " ");
-        for (i = 0; i < gsk_container_node_get_n_children (root); i++)
-          print_render_node_tree (gsk_container_node_get_child (root, i), level + 1);
-        break;
-
-      case GSK_TRANSFORM_NODE:
-        g_print ("%*s Transform\n", level * INDENT, " ");
-        print_render_node_tree (gsk_transform_node_get_child (root), level + 1);
-        break;
-
-      case GSK_COLOR_MATRIX_NODE:
-        g_print ("%*s Color Matrix\n", level * INDENT, " ");
-        print_render_node_tree (gsk_color_matrix_node_get_child (root), level + 1);
-        break;
-
-      case GSK_CROSS_FADE_NODE:
-        g_print ("%*s Crossfade(%.2f)\n", level * INDENT, " ",
-                 gsk_cross_fade_node_get_progress (root));
-        print_render_node_tree (gsk_cross_fade_node_get_start_child (root), level + 1);
-        print_render_node_tree (gsk_cross_fade_node_get_end_child (root), level + 1);
-        break;
-
-      case GSK_TEXT_NODE:
-        g_print ("%*s Text\n", level * INDENT, " ");
-        break;
-
-      case GSK_COLOR_NODE:
-        g_print ("%*s Color %s\n", level * INDENT, " ", gdk_rgba_to_string (gsk_color_node_get_color (root)));
-        break;
-
-      case GSK_SHADOW_NODE:
-        g_print ("%*s Shadow\n", level * INDENT, " ");
-        print_render_node_tree (gsk_shadow_node_get_child (root), level + 1);
-        break;
-
-      case GSK_GL_SHADER_NODE:
-        g_print ("%*s GL Shader\n", level * INDENT, " ");
-        for (i = 0; i < gsk_gl_shader_node_get_n_children (root); i++)
-          print_render_node_tree (gsk_gl_shader_node_get_child (root, i), level + 1);
-        break;
-
-      case GSK_TEXTURE_NODE:
-        g_print ("%*s Texture %p\n", level * INDENT, " ", gsk_texture_node_get_texture (root));
-        break;
-
-      case GSK_DEBUG_NODE:
-        g_print ("%*s Debug: %s\n", level * INDENT, " ", gsk_debug_node_get_message (root));
-        print_render_node_tree (gsk_debug_node_get_child (root), level + 1);
-        break;
-
-      case GSK_CLIP_NODE:
-        g_print ("%*s Clip (%f, %f, %f, %f):\n", level * INDENT, " ",
-                 root->bounds.origin.x, root->bounds.origin.y, root->bounds.size.width, root->bounds.size.height);
-        print_render_node_tree (gsk_clip_node_get_child (root), level + 1);
-        break;
-
-      default:
-        g_print ("%*s %s\n", level * INDENT, " ", g_type_name_from_instance ((GTypeInstance *) root));
-    }
-
-#undef INDENT
-}
-
-
-static void G_GNUC_UNUSED
-dump_framebuffer (const char *filename, int w, int h)
-{
-  int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, w);
-  guchar *data = g_malloc (h * stride);
-  cairo_surface_t *s;
-
-  glReadPixels (0, 0, w, h, GL_BGRA, GL_UNSIGNED_BYTE, data);
-  s = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, w, h, stride);
-  cairo_surface_write_to_png (s, filename);
-
-  cairo_surface_destroy (s);
-  g_free (data);
-}
-
-static void G_GNUC_UNUSED
-dump_node (GskRenderNode *node,
-           const char    *filename)
-{
-  const int surface_width = ceilf (node->bounds.size.width);
-  const int surface_height = ceilf (node->bounds.size.height);
-  cairo_surface_t *surface;
-  cairo_t *cr;
-
-  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
-                                        surface_width,
-                                        surface_height);
-
-  cr = cairo_create (surface);
-  cairo_save (cr);
-  cairo_translate (cr, -node->bounds.origin.x, -node->bounds.origin.y);
-  gsk_render_node_draw (node, cr);
-  cairo_restore (cr);
-  cairo_destroy (cr);
-
-  cairo_surface_write_to_png (surface, filename);
-  cairo_surface_destroy (surface);
-}
-
-static inline bool G_GNUC_PURE
-node_is_invisible (const GskRenderNode *node)
-{
-  return node->bounds.size.width == 0.0f ||
-         node->bounds.size.height == 0.0f ||
-         isnan (node->bounds.size.width) ||
-         isnan (node->bounds.size.height);
-}
-
-static inline bool G_GNUC_PURE
-graphene_rect_intersects (const graphene_rect_t *r1,
-                          const graphene_rect_t *r2)
-{
-  /* Assume both rects are already normalized, as they usually are */
-  if (r1->origin.x > (r2->origin.x + r2->size.width) ||
-      (r1->origin.x + r1->size.width) < r2->origin.x)
-    return false;
-
-  if (r1->origin.y > (r2->origin.y + r2->size.height) ||
-      (r1->origin.y + r1->size.height) < r2->origin.y)
-    return false;
-
-  return true;
-}
-
-static inline bool G_GNUC_PURE
-_graphene_rect_contains_rect (const graphene_rect_t *r1,
-                              const graphene_rect_t *r2)
-{
-  if (r2->origin.x >= r1->origin.x &&
-      (r2->origin.x + r2->size.width) <= (r1->origin.x + r1->size.width) &&
-      r2->origin.y >= r1->origin.y &&
-      (r2->origin.y + r2->size.height) <= (r1->origin.y + r1->size.height))
-    return true;
-
-  return false;
-}
-
-static inline bool G_GNUC_PURE
-equal_texture_nodes (GskRenderNode *node1,
-                     GskRenderNode *node2)
-{
-  if (gsk_render_node_get_node_type (node1) != GSK_TEXTURE_NODE ||
-      gsk_render_node_get_node_type (node2) != GSK_TEXTURE_NODE)
-    return false;
-
-  if (gsk_texture_node_get_texture (node1) !=
-      gsk_texture_node_get_texture (node2))
-    return false;
-
-  return graphene_rect_equal (&node1->bounds, &node2->bounds);
-}
-
-static inline void
-sort_border_sides (const GdkRGBA *colors,
-                   int           *indices)
-{
-  gboolean done[4] = {0, 0, 0, 0};
-  int i, k;
-  int cur = 0;
-
-  for (i = 0; i < 3; i ++)
-    {
-      if (done[i])
-        continue;
-
-      indices[cur] = i;
-      done[i] = TRUE;
-      cur ++;
-
-      for (k = i + 1; k < 4; k ++)
-        {
-          if (gdk_rgba_equal (&colors[k], &colors[i]))
-            {
-              indices[cur] = k;
-              done[k] = TRUE;
-              cur ++;
-            }
-        }
-
-      if (cur >= 4)
-        break;
-    }
-}
-
-static inline void
-init_projection_matrix (graphene_matrix_t     *out_proj,
-                        const graphene_rect_t *viewport)
-{
-  graphene_matrix_init_ortho (out_proj,
-                              viewport->origin.x,
-                              viewport->origin.x + viewport->size.width,
-                              viewport->origin.y,
-                              viewport->origin.y + viewport->size.height,
-                              ORTHO_NEAR_PLANE,
-                              ORTHO_FAR_PLANE);
-  graphene_matrix_scale (out_proj, 1, -1, 1);
-}
-
-static inline gboolean G_GNUC_PURE
-color_matrix_modifies_alpha (GskRenderNode *node)
-{
-  const graphene_matrix_t *matrix = gsk_color_matrix_node_get_color_matrix (node);
-  const graphene_vec4_t *offset = gsk_color_matrix_node_get_color_offset (node);
-  graphene_vec4_t row3;
-
-  if (graphene_vec4_get_w (offset) != 0.0f)
-    return TRUE;
-
-  graphene_matrix_get_row (matrix, 3, &row3);
-
-  return !graphene_vec4_equal (graphene_vec4_w_axis (), &row3);
-}
-
-static inline void
-gsk_rounded_rect_shrink_to_minimum (GskRoundedRect *self)
-{
-  self->bounds.size.width  = MAX (self->corner[0].width + self->corner[1].width,
-                                  self->corner[3].width + self->corner[2].width);
-  self->bounds.size.height = MAX (self->corner[0].height + self->corner[3].height,
-                                  self->corner[1].height + self->corner[2].height);
-}
-
-static inline gboolean G_GNUC_PURE
-node_supports_transform (GskRenderNode *node)
-{
-  /* Some nodes can't handle non-trivial transforms without being
-   * rendered to a texture (e.g. rotated clips, etc.). Some however
-   * work just fine, mostly because they already draw their child
-   * to a texture and just render the texture manipulated in some
-   * way, think opacity or color matrix. */
-  const guint node_type = gsk_render_node_get_node_type (node);
-
-  switch (node_type)
-    {
-      case GSK_COLOR_NODE:
-      case GSK_OPACITY_NODE:
-      case GSK_COLOR_MATRIX_NODE:
-      case GSK_TEXTURE_NODE:
-      case GSK_CROSS_FADE_NODE:
-      case GSK_LINEAR_GRADIENT_NODE:
-      case GSK_DEBUG_NODE:
-      case GSK_TEXT_NODE:
-        return TRUE;
-
-      case GSK_TRANSFORM_NODE:
-        return node_supports_transform (gsk_transform_node_get_child (node));
-
-      default:
-        return FALSE;
-    }
-  return FALSE;
-}
-
-static inline void
-load_vertex_data_with_region (GskQuadVertex          vertex_data[GL_N_VERTICES],
-                              const graphene_rect_t *bounds,
-                              RenderOpBuilder       *builder,
-                              const TextureRegion   *r,
-                              gboolean               flip_y)
-{
-  const float min_x = builder->dx + bounds->origin.x;
-  const float min_y = builder->dy + bounds->origin.y;
-  const float max_x = min_x + bounds->size.width;
-  const float max_y = min_y + bounds->size.height;
-  const float y1 = flip_y ? r->y2 : r->y;
-  const float y2 = flip_y ? r->y  : r->y2;
-
-  vertex_data[0].position[0] = min_x;
-  vertex_data[0].position[1] = min_y;
-  vertex_data[0].uv[0] = r->x;
-  vertex_data[0].uv[1] = y1;
-
-  vertex_data[1].position[0] = min_x;
-  vertex_data[1].position[1] = max_y;
-  vertex_data[1].uv[0] = r->x;
-  vertex_data[1].uv[1] = y2;
-
-  vertex_data[2].position[0] = max_x;
-  vertex_data[2].position[1] = min_y;
-  vertex_data[2].uv[0] = r->x2;
-  vertex_data[2].uv[1] = y1;
-
-  vertex_data[3].position[0] = max_x;
-  vertex_data[3].position[1] = max_y;
-  vertex_data[3].uv[0] = r->x2;
-  vertex_data[3].uv[1] = y2;
-
-  vertex_data[4].position[0] = min_x;
-  vertex_data[4].position[1] = max_y;
-  vertex_data[4].uv[0] = r->x;
-  vertex_data[4].uv[1] = y2;
-
-  vertex_data[5].position[0] = max_x;
-  vertex_data[5].position[1] = min_y;
-  vertex_data[5].uv[0] = r->x2;
-  vertex_data[5].uv[1] = y1;
-}
-
-static inline void
-load_float_vertex_data (GskQuadVertex    vertex_data[GL_N_VERTICES],
-                        RenderOpBuilder *builder,
-                        float            x,
-                        float            y,
-                        float            width,
-                        float            height)
-{
-  const float min_x = builder->dx + x;
-  const float min_y = builder->dy + y;
-  const float max_x = min_x + width;
-  const float max_y = min_y + height;
-
-  vertex_data[0].position[0] = min_x;
-  vertex_data[0].position[1] = min_y;
-  vertex_data[0].uv[0] = 0;
-  vertex_data[0].uv[1] = 0;
-
-  vertex_data[1].position[0] = min_x;
-  vertex_data[1].position[1] = max_y;
-  vertex_data[1].uv[0] = 0;
-  vertex_data[1].uv[1] = 1;
-
-  vertex_data[2].position[0] = max_x;
-  vertex_data[2].position[1] = min_y;
-  vertex_data[2].uv[0] = 1;
-  vertex_data[2].uv[1] = 0;
-
-  vertex_data[3].position[0] = max_x;
-  vertex_data[3].position[1] = max_y;
-  vertex_data[3].uv[0] = 1;
-  vertex_data[3].uv[1] = 1;
-
-  vertex_data[4].position[0] = min_x;
-  vertex_data[4].position[1] = max_y;
-  vertex_data[4].uv[0] = 0;
-  vertex_data[4].uv[1] = 1;
-
-  vertex_data[5].position[0] = max_x;
-  vertex_data[5].position[1] = min_y;
-  vertex_data[5].uv[0] = 1;
-  vertex_data[5].uv[1] = 0;
-}
-
-static void
-load_vertex_data (GskQuadVertex          vertex_data[GL_N_VERTICES],
-                  const graphene_rect_t *bounds,
-                  RenderOpBuilder       *builder)
-{
-  load_float_vertex_data (vertex_data, builder,
-                          bounds->origin.x, bounds->origin.y,
-                          bounds->size.width, bounds->size.height);
-}
-
-static void
-fill_vertex_data (GskQuadVertex vertex_data[GL_N_VERTICES],
-                  const float   min_x,
-                  const float   min_y,
-                  const float   max_x,
-                  const float   max_y)
-{
-  vertex_data[0].position[0] = min_x;
-  vertex_data[0].position[1] = min_y;
-  vertex_data[0].uv[0] = 0;
-  vertex_data[0].uv[1] = 1;
-
-  vertex_data[1].position[0] = min_x;
-  vertex_data[1].position[1] = max_y;
-  vertex_data[1].uv[0] = 0;
-  vertex_data[1].uv[1] = 0;
-
-  vertex_data[2].position[0] = max_x;
-  vertex_data[2].position[1] = min_y;
-  vertex_data[2].uv[0] = 1;
-  vertex_data[2].uv[1] = 1;
-
-  vertex_data[3].position[0] = max_x;
-  vertex_data[3].position[1] = max_y;
-  vertex_data[3].uv[0] = 1;
-  vertex_data[3].uv[1] = 0;
-
-  vertex_data[4].position[0] = min_x;
-  vertex_data[4].position[1] = max_y;
-  vertex_data[4].uv[0] = 0;
-  vertex_data[4].uv[1] = 0;
-
-  vertex_data[5].position[0] = max_x;
-  vertex_data[5].position[1] = min_y;
-  vertex_data[5].uv[0] = 1;
-  vertex_data[5].uv[1] = 1;
-}
-
-static void
-load_offscreen_vertex_data (GskQuadVertex    vertex_data[GL_N_VERTICES],
-                            GskRenderNode   *node,
-                            RenderOpBuilder *builder)
-{
-  const float min_x = builder->dx + node->bounds.origin.x;
-  const float min_y = builder->dy + node->bounds.origin.y;
-  const float max_x = min_x + node->bounds.size.width;
-  const float max_y = min_y + node->bounds.size.height;
-
-  fill_vertex_data (vertex_data,
-                    min_x, min_y,
-                    max_x, max_y);
-}
-
-
-static void gsk_gl_renderer_setup_render_mode (GskGLRenderer   *self);
-static gboolean add_offscreen_ops             (GskGLRenderer   *self,
-                                               RenderOpBuilder       *builder,
-                                               const graphene_rect_t *bounds,
-                                               GskRenderNode         *child_node,
-                                               TextureRegion         *region_out,
-                                               gboolean              *is_offscreen,
-                                               guint                  flags) G_GNUC_WARN_UNUSED_RESULT;
-static void gsk_gl_renderer_add_render_ops     (GskGLRenderer   *self,
-                                                GskRenderNode   *node,
-                                                RenderOpBuilder *builder);
-
-struct _GskGLRenderer
-{
-  GskRenderer parent_instance;
-
-  int scale_factor;
-
-  GdkGLContext *gl_context;
-  GskGLDriver *gl_driver;
-  GskGLProfiler *gl_profiler;
-
-  GskGLRendererPrograms *programs;
-
-  RenderOpBuilder op_builder;
-
-  GskGLTextureAtlases *atlases;
-  GskGLGlyphCache *glyph_cache;
-  GskGLIconCache *icon_cache;
-  GskGLShadowCache shadow_cache;
-
-#ifdef G_ENABLE_DEBUG
-  struct {
-    GQuark frames;
-  } profile_counters;
-  struct {
-    GQuark cpu_time;
-    GQuark gpu_time;
-  } profile_timers;
-#endif
-
-  cairo_region_t *render_region;
-};
-
-struct _GskGLRendererClass
-{
-  GskRendererClass parent_class;
-};
-
-G_DEFINE_TYPE (GskGLRenderer, gsk_gl_renderer, GSK_TYPE_RENDERER)
-
-static void
-init_shader_builder (GskGLRenderer       *self,
-                     GskGLShaderBuilder  *shader_builder)
-{
-#ifdef G_ENABLE_DEBUG
-  if (GSK_RENDERER_DEBUG_CHECK (GSK_RENDERER (self), SHADERS))
-    shader_builder->debugging = TRUE;
-#endif
-
-  if (gdk_gl_context_get_use_es (self->gl_context))
-    {
-      gsk_gl_shader_builder_set_glsl_version (shader_builder, SHADER_VERSION_GLES);
-      shader_builder->gles = TRUE;
-    }
-  else if (gdk_gl_context_is_legacy (self->gl_context))
-    {
-      int maj, min;
-
-      gdk_gl_context_get_version (self->gl_context, &maj, &min);
-
-      if (maj == 3)
-        gsk_gl_shader_builder_set_glsl_version (shader_builder, SHADER_VERSION_GL3_LEGACY);
-      else
-        gsk_gl_shader_builder_set_glsl_version (shader_builder, SHADER_VERSION_GL2_LEGACY);
-
-      shader_builder->legacy = TRUE;
-        }
-  else
-    {
-      gsk_gl_shader_builder_set_glsl_version (shader_builder, SHADER_VERSION_GL3);
-      shader_builder->gl3 = TRUE;
-    }
-}
-
-static GdkRGBA BLACK = {0, 0, 0, 1};
-static void G_GNUC_UNUSED
-add_rect_outline_ops (GskGLRenderer         *self,
-                      RenderOpBuilder       *builder,
-                      const graphene_rect_t *rect)
-{
-  ops_set_program (builder, &self->programs->color_program);
-  ops_set_color (builder, &BLACK);
-
-  load_vertex_data (ops_draw (builder, NULL),
-                    &GRAPHENE_RECT_INIT (rect->origin.x, rect->origin.y, 1, rect->size.height),
-                    builder);
-  load_vertex_data (ops_draw (builder, NULL),
-                    &GRAPHENE_RECT_INIT (rect->origin.x, rect->origin.y, rect->size.width, 1),
-                    builder);
-  load_vertex_data (ops_draw (builder, NULL),
-                    &GRAPHENE_RECT_INIT (rect->origin.x + rect->size.width - 1,rect->origin.y,
-                                         1, rect->size.height),
-                    builder);
-  load_vertex_data (ops_draw (builder, NULL),
-                    &GRAPHENE_RECT_INIT (rect->origin.x, rect->origin.y + rect->size.height - 1,
-                                         rect->size.width, 1),
-                    builder);
-}
-
-static inline GskRoundedRect
-transform_rect (GskGLRenderer        *self,
-                RenderOpBuilder      *builder,
-                const GskRoundedRect *rect)
-{
-  GskRoundedRect r;
-
-  r.bounds.origin.x = builder->dx + rect->bounds.origin.x;
-  r.bounds.origin.y = builder->dy + rect->bounds.origin.y;
-  r.bounds.size = rect->bounds.size;
-
-  r.corner[0] = rect->corner[0];
-  r.corner[1] = rect->corner[1];
-  r.corner[2] = rect->corner[2];
-  r.corner[3] = rect->corner[3];
-
-  return r;
-}
-
-static inline void
-render_fallback_node (GskGLRenderer   *self,
-                      GskRenderNode   *node,
-                      RenderOpBuilder *builder)
-{
-  const float scale_x = builder->scale_x;
-  const float scale_y = builder->scale_y;
-  const int surface_width = ceilf (node->bounds.size.width * scale_x);
-  const int surface_height = ceilf (node->bounds.size.height * scale_y);
-  GdkTexture *texture;
-  cairo_surface_t *surface;
-  cairo_surface_t *rendered_surface;
-  cairo_t *cr;
-  int cached_id;
-  int texture_id;
-  GskTextureKey key;
-
-  if (surface_width <= 0 ||
-      surface_height <= 0)
-    return;
-
-  key.pointer = node;
-  key.pointer_is_child = FALSE;
-  key.scale_x = scale_x;
-  key.scale_y = scale_y;
-  key.filter = GL_NEAREST;
-
-  cached_id = gsk_gl_driver_get_texture_for_key (self->gl_driver, &key);
-
-  if (cached_id != 0)
-    {
-      ops_set_program (builder, &self->programs->blit_program);
-      ops_set_texture (builder, cached_id);
-      load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
-      return;
-    }
-
-
-  /* We first draw the recording surface on an image surface,
-   * just because the scaleY(-1) later otherwise screws up the
-   * rendering... */
-  {
-    rendered_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
-                                                   surface_width,
-                                                   surface_height);
-
-    cairo_surface_set_device_scale (rendered_surface, scale_x, scale_y);
-    cr = cairo_create (rendered_surface);
-
-    cairo_save (cr);
-    cairo_translate (cr, - floorf (node->bounds.origin.x), - floorf (node->bounds.origin.y));
-    gsk_render_node_draw (node, cr);
-    cairo_restore (cr);
-    cairo_destroy (cr);
-  }
-
-  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
-                                        surface_width,
-                                        surface_height);
-  cairo_surface_set_device_scale (surface, scale_x, scale_y);
-  cr = cairo_create (surface);
-
-  /* We draw upside down here, so it matches what GL does. */
-  cairo_save (cr);
-  cairo_scale (cr, 1, -1);
-  cairo_translate (cr, 0, - surface_height / scale_y);
-  cairo_set_source_surface (cr, rendered_surface, 0, 0);
-  cairo_rectangle (cr, 0, 0, surface_width / scale_x, surface_height / scale_y);
-  cairo_fill (cr);
-  cairo_restore (cr);
-
-#ifdef G_ENABLE_DEBUG
-  if (GSK_RENDERER_DEBUG_CHECK (GSK_RENDERER (self), FALLBACK))
-    {
-      cairo_move_to (cr, 0, 0);
-      cairo_rectangle (cr, 0, 0, node->bounds.size.width, node->bounds.size.height);
-      if (gsk_render_node_get_node_type (node) == GSK_CAIRO_NODE)
-        cairo_set_source_rgba (cr, 0.3, 0, 1, 0.25);
-      else
-        cairo_set_source_rgba (cr, 1, 0, 0, 0.25);
-      cairo_fill_preserve (cr);
-      if (gsk_render_node_get_node_type (node) == GSK_CAIRO_NODE)
-        cairo_set_source_rgba (cr, 0.3, 0, 1, 1);
-      else
-        cairo_set_source_rgba (cr, 1, 0, 0, 1);
-      cairo_stroke (cr);
-    }
-#endif
-  cairo_destroy (cr);
-
-
-  /* Upload the Cairo surface to a GL texture */
-  texture_id = gsk_gl_driver_create_texture (self->gl_driver,
-                                             surface_width,
-                                             surface_height);
-  gsk_gl_driver_bind_source_texture (self->gl_driver, texture_id);
-
-  texture = gdk_texture_new_for_surface (surface);
-  gsk_gl_driver_init_texture (self->gl_driver,
-                              texture_id,
-                              texture,
-                              GL_NEAREST, GL_NEAREST);
-
-  if (gdk_gl_context_has_debug (self->gl_context))
-    gdk_gl_context_label_object_printf  (self->gl_context, GL_TEXTURE, texture_id,
-                                         "Fallback %s %d",
-                                         g_type_name_from_instance ((GTypeInstance *) node),
-                                         texture_id);
-
-  g_object_unref (texture);
-  cairo_surface_destroy (surface);
-  cairo_surface_destroy (rendered_surface);
-
-  gsk_gl_driver_set_texture_for_key (self->gl_driver, &key, texture_id);
-
-  ops_set_program (builder, &self->programs->blit_program);
-  ops_set_texture (builder, texture_id);
-  load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
-}
-
-static inline void
-render_text_node (GskGLRenderer   *self,
-                  GskRenderNode   *node,
-                  RenderOpBuilder *builder,
-                  const GdkRGBA   *color,
-                  gboolean         force_color)
-{
-  const PangoFont *font = gsk_text_node_get_font (node);
-  const PangoGlyphInfo *glyphs = gsk_text_node_get_glyphs (node, NULL);
-  const float text_scale = MAX (builder->scale_x, builder->scale_y); /* TODO: Fix for uneven scales? */
-  const graphene_point_t *offset = gsk_text_node_get_offset (node);
-  const guint num_glyphs = gsk_text_node_get_num_glyphs (node);
-  const float x = offset->x + builder->dx;
-  const float y = offset->y + builder->dy;
-  int i;
-  int x_position = 0;
-  GlyphCacheKey lookup;
-
-  /* If the font has color glyphs, we don't need to recolor anything */
-  if (!force_color && gsk_text_node_has_color_glyphs (node))
-    {
-      ops_set_program (builder, &self->programs->blit_program);
-    }
-  else
-    {
-      ops_set_program (builder, &self->programs->coloring_program);
-      ops_set_color (builder, color);
-    }
-
-  memset (&lookup, 0, sizeof (CacheKeyData));
-  lookup.data.font = (PangoFont *)font;
-  lookup.data.scale = (guint) (text_scale * 1024);
-
-  /* We use one quad per character */
-  for (i = 0; i < num_glyphs; i++)
-    {
-      const PangoGlyphInfo *gi = &glyphs[i];
-      const GskGLCachedGlyph *glyph;
-      float glyph_x, glyph_y, glyph_x2, glyph_y2;
-      float tx, ty, tx2, ty2;
-      float cx;
-      float cy;
-
-      if (gi->glyph == PANGO_GLYPH_EMPTY)
-        continue;
-
-      cx = (float)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
-      cy = (float)(gi->geometry.y_offset) / PANGO_SCALE;
-
-      glyph_cache_key_set_glyph_and_shift (&lookup, gi->glyph, x + cx, y + cy);
-
-      gsk_gl_glyph_cache_lookup_or_add (self->glyph_cache,
-                                        &lookup,
-                                        self->gl_driver,
-                                        &glyph);
-
-      if (glyph->texture_id == 0)
-        goto next;
-
-      ops_set_texture (builder, glyph->texture_id);
-
-      tx  = glyph->tx;
-      ty  = glyph->ty;
-      tx2 = tx + glyph->tw;
-      ty2 = ty + glyph->th;
-
-      glyph_x = floor (x + cx + 0.125) + glyph->draw_x;
-      glyph_y = floor (y + cy + 0.125) + glyph->draw_y;
-      glyph_x2 = glyph_x + glyph->draw_width;
-      glyph_y2 = glyph_y + glyph->draw_height;
-
-      ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
-        { { glyph_x,  glyph_y  }, { tx,  ty  }, },
-        { { glyph_x,  glyph_y2 }, { tx,  ty2 }, },
-        { { glyph_x2, glyph_y  }, { tx2, ty  }, },
-
-        { { glyph_x2, glyph_y2 }, { tx2, ty2 }, },
-        { { glyph_x,  glyph_y2 }, { tx,  ty2 }, },
-        { { glyph_x2, glyph_y  }, { tx2, ty  }, },
-      });
-
-next:
-      x_position += gi->geometry.width;
-    }
-}
-
-static inline void
-render_border_node (GskGLRenderer   *self,
-                    GskRenderNode   *node,
-                    RenderOpBuilder *builder)
-{
-  const GdkRGBA *colors = gsk_border_node_get_colors (node);
-  const GskRoundedRect *rounded_outline = gsk_border_node_get_outline (node);
-  const float *widths = gsk_border_node_get_widths (node);
-  int i;
-  struct {
-    float w;
-    float h;
-  } sizes[4];
-
-  if (gsk_border_node_get_uniform (node))
-    {
-      ops_set_program (builder, &self->programs->inset_shadow_program);
-      ops_set_inset_shadow (builder, transform_rect (self, builder, rounded_outline),
-                            widths[0], &colors[0], 0, 0);
-
-      load_vertex_data (ops_draw (builder, NULL), &node->bounds, builder);
-      return;
-    }
-
-  /* Top left */
-  if (widths[3] > 0)
-    sizes[0].w = MAX (widths[3], rounded_outline->corner[0].width);
-  else
-    sizes[0].w = 0;
-
-  if (widths[0] > 0)
-    sizes[0].h = MAX (widths[0], rounded_outline->corner[0].height);
-  else
-    sizes[0].h = 0;
-
-  /* Top right */
-  if (widths[1] > 0)
-    sizes[1].w = MAX (widths[1], rounded_outline->corner[1].width);
-  else
-    sizes[1].w = 0;
-
-  if (widths[0] > 0)
-    sizes[1].h = MAX (widths[0], rounded_outline->corner[1].height);
-  else
-    sizes[1].h = 0;
-
-  /* Bottom right */
-  if (widths[1] > 0)
-    sizes[2].w = MAX (widths[1], rounded_outline->corner[2].width);
-  else
-    sizes[2].w = 0;
-
-  if (widths[2] > 0)
-    sizes[2].h = MAX (widths[2], rounded_outline->corner[2].height);
-  else
-    sizes[2].h = 0;
-
-
-  /* Bottom left */
-  if (widths[3] > 0)
-    sizes[3].w = MAX (widths[3], rounded_outline->corner[3].width);
-  else
-    sizes[3].w = 0;
-
-  if (widths[2] > 0)
-    sizes[3].h = MAX (widths[2], rounded_outline->corner[3].height);
-  else
-    sizes[3].h = 0;
-
-  {
-    const float min_x = builder->dx + node->bounds.origin.x;
-    const float min_y = builder->dy + node->bounds.origin.y;
-    const float max_x = min_x + node->bounds.size.width;
-    const float max_y = min_y + node->bounds.size.height;
-    const GskQuadVertex side_data[4][6] = {
-      /* Top */
-      {
-        { { min_x,              min_y              }, { 0, 1 }, }, /* Upper left */
-        { { min_x + sizes[0].w, min_y + sizes[0].h }, { 0, 0 }, }, /* Lower left */
-        { { max_x,              min_y              }, { 1, 1 }, }, /* Upper right */
-
-        { { max_x - sizes[1].w, min_y + sizes[1].h }, { 1, 0 }, }, /* Lower right */
-        { { min_x + sizes[0].w, min_y + sizes[0].h }, { 0, 0 }, }, /* Lower left */
-        { { max_x,              min_y              }, { 1, 1 }, }, /* Upper right */
-      },
-      /* Right */
-      {
-        { { max_x - sizes[1].w, min_y + sizes[1].h }, { 0, 1 }, }, /* Upper left */
-        { { max_x - sizes[2].w, max_y - sizes[2].h }, { 0, 0 }, }, /* Lower left */
-        { { max_x,              min_y              }, { 1, 1 }, }, /* Upper right */
-
-        { { max_x,              max_y              }, { 1, 0 }, }, /* Lower right */
-        { { max_x - sizes[2].w, max_y - sizes[2].h }, { 0, 0 }, }, /* Lower left */
-        { { max_x,              min_y              }, { 1, 1 }, }, /* Upper right */
-      },
-      /* Bottom */
-      {
-        { { min_x + sizes[3].w, max_y - sizes[3].h }, { 0, 1 }, }, /* Upper left */
-        { { min_x,              max_y              }, { 0, 0 }, }, /* Lower left */
-        { { max_x - sizes[2].w, max_y - sizes[2].h }, { 1, 1 }, }, /* Upper right */
-
-        { { max_x,              max_y              }, { 1, 0 }, }, /* Lower right */
-        { { min_x            ,  max_y              }, { 0, 0 }, }, /* Lower left */
-        { { max_x - sizes[2].w, max_y - sizes[2].h }, { 1, 1 }, }, /* Upper right */
-      },
-      /* Left */
-      {
-        { { min_x,              min_y              }, { 0, 1 }, }, /* Upper left */
-        { { min_x,              max_y              }, { 0, 0 }, }, /* Lower left */
-        { { min_x + sizes[0].w, min_y + sizes[0].h }, { 1, 1 }, }, /* Upper right */
-
-        { { min_x + sizes[3].w, max_y - sizes[3].h }, { 1, 0 }, }, /* Lower right */
-        { { min_x,              max_y              }, { 0, 0 }, }, /* Lower left */
-        { { min_x + sizes[0].w, min_y + sizes[0].h }, { 1, 1 }, }, /* Upper right */
-      }
-    };
-    int indices[4] = { 0, 1, 2, 3 };
-    GskRoundedRect outline;
-
-    /* We sort them by color */
-    sort_border_sides (colors, indices);
-
-    /* Prepare outline */
-    outline = transform_rect (self, builder, rounded_outline);
-
-    ops_set_program (builder, &self->programs->border_program);
-    ops_set_border_width (builder, widths);
-    ops_set_border (builder, &outline);
-
-    for (i = 0; i < 4; i ++)
-      {
-        if (widths[indices[i]] > 0)
-          {
-            ops_set_border_color (builder, &colors[indices[i]]);
-            ops_draw (builder, side_data[indices[i]]);
-          }
-      }
-  }
-}
-
-static inline void
-render_color_node (GskGLRenderer   *self,
-                   GskRenderNode   *node,
-                   RenderOpBuilder *builder)
-{
-  ops_set_program (builder, &self->programs->color_program);
-  ops_set_color (builder, gsk_color_node_get_color (node));
-  load_vertex_data (ops_draw (builder, NULL), &node->bounds, builder);
-}
-
-static inline void
-upload_texture (GskGLRenderer *self,
-                GdkTexture    *texture,
-                TextureRegion *out_region)
-{
-  if (texture->width <= 128 &&
-      texture->height <= 128 &&
-      !GDK_IS_GL_TEXTURE (texture))
-    {
-      const IconData *icon_data;
-
-      gsk_gl_icon_cache_lookup_or_add (self->icon_cache,
-                                       texture,
-                                       &icon_data);
-
-      out_region->texture_id = icon_data->texture_id;
-      out_region->x = icon_data->x;
-      out_region->y = icon_data->y;
-      out_region->x2 = icon_data->x2;
-      out_region->y2 = icon_data->y2;
-    }
-  else
-    {
-
-      out_region->texture_id =
-          gsk_gl_driver_get_texture_for_texture (self->gl_driver,
-                                                 texture,
-                                                 GL_LINEAR,
-                                                 GL_LINEAR);
-
-      out_region->x  = 0;
-      out_region->y  = 0;
-      out_region->x2 = 1;
-      out_region->y2 = 1;
-    }
-}
-
-static inline void
-render_texture_node (GskGLRenderer       *self,
-                     GskRenderNode       *node,
-                     RenderOpBuilder     *builder)
-{
-  GdkTexture *texture = gsk_texture_node_get_texture (node);
-  const int max_texture_size = gsk_gl_driver_get_max_texture_size (self->gl_driver);
-
-  if (texture->width > max_texture_size || texture->height > max_texture_size)
-    {
-      const float min_x = builder->dx + node->bounds.origin.x;
-      const float min_y = builder->dy + node->bounds.origin.y;
-      const float max_x = min_x + node->bounds.size.width;
-      const float max_y = min_y + node->bounds.size.height;
-      const float scale_x = (max_x - min_x) / texture->width;
-      const float scale_y = (max_y - min_y) / texture->height;
-      TextureSlice *slices;
-      guint n_slices;
-      guint i;
-
-      gsk_gl_driver_slice_texture (self->gl_driver, texture, &slices, &n_slices);
-
-      ops_set_program (builder, &self->programs->blit_program);
-      for (i = 0; i < n_slices; i ++)
-        {
-          const TextureSlice *slice = &slices[i];
-          float x1, x2, y1, y2;
-
-          x1 = min_x + (scale_x * slice->rect.x);
-          x2 = x1 + (slice->rect.width * scale_x);
-          y1 = min_y + (scale_y * slice->rect.y);
-          y2 = y1 + (slice->rect.height * scale_y);
-
-          ops_set_texture (builder, slice->texture_id);
-          ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
-            { { x1, y1 }, { 0, 0 }, },
-            { { x1, y2 }, { 0, 1 }, },
-            { { x2, y1 }, { 1, 0 }, },
-
-            { { x2, y2 }, { 1, 1 }, },
-            { { x1, y2 }, { 0, 1 }, },
-            { { x2, y1 }, { 1, 0 }, },
-          });
-        }
-    }
-  else
-    {
-      TextureRegion r;
-
-      upload_texture (self, texture, &r);
-
-      ops_set_program (builder, &self->programs->blit_program);
-      ops_set_texture (builder, r.texture_id);
-
-      load_vertex_data_with_region (ops_draw (builder, NULL),
-                                    &node->bounds, builder,
-                                    &r,
-                                    FALSE);
-    }
-}
-
-static Program *
-compile_glshader (GskGLRenderer  *self,
-                  GskGLShader    *shader,
-                  GError        **error)
-{
-  GskGLShaderBuilder shader_builder;
-  const char *shader_source;
-  gsize shader_source_len;
-  int n_uniforms;
-  const GskGLUniform *uniforms;
-  GBytes *bytes;
-  int n_required_textures = gsk_gl_shader_get_n_textures (shader);
-  int program_id;
-  Program *program;
-
-  bytes = gsk_gl_shader_get_source (shader);
-  shader_source = g_bytes_get_data (bytes, &shader_source_len);
-  uniforms = gsk_gl_shader_get_uniforms (shader, &n_uniforms);
-
-  if (n_uniforms > G_N_ELEMENTS (program->glshader.args_locations))
-    {
-      g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_UNSUPPORTED_FORMAT,
-                   "GLShaderNode supports max %d custom uniforms", (int)G_N_ELEMENTS (program->glshader.args_locations));
-      return NULL;
-    }
-
-  if (n_required_textures > G_N_ELEMENTS (program->glshader.texture_locations))
-    {
-      g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_UNSUPPORTED_FORMAT,
-                   "GLShaderNode supports max %d texture sources", (int)(G_N_ELEMENTS (program->glshader.texture_locations)));
-      return NULL;
-    }
-
-  gsk_gl_shader_builder_init (&shader_builder,
-                              "/org/gtk/libgsk/gl/preamble.glsl",
-                              "/org/gtk/libgsk/gl/preamble.vs.glsl",
-                              "/org/gtk/libgsk/gl/preamble.fs.glsl");
-
-  init_shader_builder (self, &shader_builder);
-  program_id = gsk_gl_shader_builder_create_program (&shader_builder,
-                                                     "/org/gtk/libgsk/gl/custom.glsl",
-                                                     shader_source, shader_source_len,
-                                                     error);
-  gsk_gl_shader_builder_finish (&shader_builder);
-
-  if (program_id  < 0)
-    return NULL;
-
-  program = gsk_gl_renderer_create_custom_program (self, shader);
-
-  program->id = program_id;
-  INIT_COMMON_UNIFORM_LOCATION (program, alpha);
-  INIT_COMMON_UNIFORM_LOCATION (program, clip_rect);
-  INIT_COMMON_UNIFORM_LOCATION (program, viewport);
-  INIT_COMMON_UNIFORM_LOCATION (program, projection);
-  INIT_COMMON_UNIFORM_LOCATION (program, modelview);
-  program->glshader.size_location = glGetUniformLocation(program->id, "u_size");
-  program->glshader.texture_locations[0] = glGetUniformLocation(program->id, "u_texture1");
-  program->glshader.texture_locations[1] = glGetUniformLocation(program->id, "u_texture2");
-  program->glshader.texture_locations[2] = glGetUniformLocation(program->id, "u_texture3");
-  program->glshader.texture_locations[3] = glGetUniformLocation(program->id, "u_texture4");
-
-  /* We use u_texture1 for the texture 0 in the glshaders, so alias it here so we can use the regular setters */
-  program->source_location = program->glshader.texture_locations[0];
-
-  for (int i = 0; i < G_N_ELEMENTS (program->glshader.args_locations); i++)
-    {
-      if (i < n_uniforms)
-        {
-          program->glshader.args_locations[i] = glGetUniformLocation(program->id, uniforms[i].name);
-          /* This isn't necessary a hard error, you might declare uniforms that are not actually
-             always used, for instance if you have an "API" in uniforms for multiple shaders. */
-          if (program->glshader.args_locations[i] == -1)
-            g_debug ("Declared uniform `%s` not found in GskGLShader", uniforms[i].name);
-        }
-      else
-        program->glshader.args_locations[i] = -1;
-    }
-
-  return program;
-}
-
-gboolean
-gsk_gl_renderer_try_compile_gl_shader (GskGLRenderer  *self,
-                                       GskGLShader    *shader,
-                                       GError        **error)
-{
-  Program *program;
-
-  gdk_gl_context_make_current (self->gl_context);
-
-  /* Maybe we tried to compile it already? */
-  program = gsk_gl_renderer_lookup_custom_program (self, shader);
-  if (program != NULL)
-    {
-      if (program->id > 0)
-        return TRUE;
-      else
-        {
-          g_propagate_error (error, g_error_copy (program->glshader.compile_error));
-          return FALSE;
-        }
-    }
-
-  program = compile_glshader (self, shader, error);
-  return program != NULL;
-}
-
-static inline void
-render_gl_shader_node (GskGLRenderer       *self,
-                       GskRenderNode       *node,
-                       RenderOpBuilder     *builder)
-{
-  GskGLShader *shader = gsk_gl_shader_node_get_shader (node);
-  Program *program = gsk_gl_renderer_lookup_custom_program (self, shader);
-  int n_children = gsk_gl_shader_node_get_n_children (node);
-
-  if (program == NULL)
-    {
-      GError *error = NULL;
-
-      program = compile_glshader (self, shader, &error);
-      if (program == NULL)
-        {
-          /* We create the program anyway (in a failed state), so that any compiler warnings or other are only reported once */
-          program = gsk_gl_renderer_create_custom_program (self, shader);
-          program->id = -1;
-          program->glshader.compile_error = error;
-
-          g_warning ("Failed to compile gl shader: %s", error->message);
-        }
-    }
-
-  if (program->id >= 0 && n_children <= G_N_ELEMENTS (program->glshader.texture_locations))
-    {
-      GBytes *args;
-      TextureRegion regions[4];
-      gboolean is_offscreen[4];
-      for (guint i = 0; i < n_children; i++)
-        {
-          GskRenderNode *child = gsk_gl_shader_node_get_child (node, i);
-          if (!add_offscreen_ops (self, builder,
-                                  &node->bounds,
-                                  child,
-                                  &regions[i], &is_offscreen[i],
-                                  FORCE_OFFSCREEN | RESET_CLIP))
-            return;
-        }
-
-      args = gsk_gl_shader_node_get_args (node);
-      ops_set_program (builder, program);
-
-      ops_set_gl_shader_args (builder, shader, node->bounds.size.width, node->bounds.size.height, g_bytes_get_data (args, NULL));
-      for (guint i = 0; i < n_children; i++)
-        {
-          if (i == 0)
-            ops_set_texture (builder, regions[i].texture_id);
-          else
-            ops_set_extra_texture (builder, regions[i].texture_id, i);
-        }
-
-      load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
-    }
-  else
-    {
-      static GdkRGBA pink = { 255 / 255., 105 / 255., 180 / 255., 1.0 };
-      ops_set_program (builder, &self->programs->color_program);
-      ops_set_color (builder, &pink);
-      load_vertex_data (ops_draw (builder, NULL), &node->bounds, builder);
-    }
-}
-
-/* Returns TRUE if applying @transform to @bounds
- * yields an axis-aligned rectangle
- */
-static gboolean
-result_is_axis_aligned (GskTransform          *transform,
-                        const graphene_rect_t *bounds)
-{
-  graphene_matrix_t m;
-  graphene_quad_t q;
-  graphene_rect_t b;
-  graphene_point_t b1, b2;
-  const graphene_point_t *p;
-  int i;
-
-  gsk_transform_to_matrix (transform, &m);
-  gsk_matrix_transform_rect (&m, bounds, &q);
-  graphene_quad_bounds (&q, &b);
-  graphene_rect_get_top_left (&b, &b1);
-  graphene_rect_get_bottom_right (&b, &b2);
-
-  for (i = 0; i < 4; i++)
-    {
-      p = graphene_quad_get_point (&q, i);
-      if (fabs (p->x - b1.x) > FLT_EPSILON && fabs (p->x - b2.x) > FLT_EPSILON)
-        return FALSE;
-      if (fabs (p->y - b1.y) > FLT_EPSILON && fabs (p->y - b2.y) > FLT_EPSILON)
-        return FALSE;
-    }
-
-  return TRUE;
-}
-
-static inline void
-render_transform_node (GskGLRenderer   *self,
-                       GskRenderNode   *node,
-                       RenderOpBuilder *builder)
-{
-  GskTransform *node_transform = gsk_transform_node_get_transform (node);
-  const GskTransformCategory category = gsk_transform_get_category (node_transform);
-  GskRenderNode *child = gsk_transform_node_get_child (node);
-
-  switch (category)
-    {
-    case GSK_TRANSFORM_CATEGORY_IDENTITY:
-      gsk_gl_renderer_add_render_ops (self, child, builder);
-    break;
-
-    case GSK_TRANSFORM_CATEGORY_2D_TRANSLATE:
-      {
-        float dx, dy;
-
-        gsk_transform_to_translate (node_transform, &dx, &dy);
-
-        ops_offset (builder, dx, dy);
-        gsk_gl_renderer_add_render_ops (self, child, builder);
-        ops_offset (builder, -dx, -dy);
-      }
-    break;
-
-    case GSK_TRANSFORM_CATEGORY_2D_AFFINE:
-      {
-        ops_push_modelview (builder, node_transform);
-        gsk_gl_renderer_add_render_ops (self, child, builder);
-        ops_pop_modelview (builder);
-      }
-    break;
-
-    case GSK_TRANSFORM_CATEGORY_2D:
-    case GSK_TRANSFORM_CATEGORY_3D:
-    case GSK_TRANSFORM_CATEGORY_ANY:
-    case GSK_TRANSFORM_CATEGORY_UNKNOWN:
-      {
-        TextureRegion region;
-        gboolean is_offscreen;
-
-        if (node_supports_transform (child))
-          {
-            ops_push_modelview (builder, node_transform);
-            gsk_gl_renderer_add_render_ops (self, child, builder);
-            ops_pop_modelview (builder);
-          }
-        else
-          {
-            int filter_flag = 0;
-
-            if (!result_is_axis_aligned (node_transform, &child->bounds))
-              filter_flag = LINEAR_FILTER;
-
-            if (add_offscreen_ops (self, builder,
-                                   &child->bounds,
-                                   child,
-                                   &region, &is_offscreen,
-                                   RESET_CLIP | filter_flag))
-              {
-                /* For non-trivial transforms, we draw everything on a texture and then
-                 * draw the texture transformed. */
-                /* TODO: We should compute a modelview containing only the "non-trivial"
-                 *       part (e.g. the rotation) and use that. We want to keep the scale
-                 *       for the texture.
-                 */
-                ops_push_modelview (builder, node_transform);
-                ops_set_texture (builder, region.texture_id);
-                ops_set_program (builder, &self->programs->blit_program);
-
-                load_vertex_data_with_region (ops_draw (builder, NULL),
-                                              &child->bounds, builder,
-                                              &region,
-                                              is_offscreen);
-                ops_pop_modelview (builder);
-              }
-          }
-      }
-      break;
-
-    default:
-      g_assert_not_reached ();
-      break;
-    }
-}
-
-static inline void
-render_opacity_node (GskGLRenderer   *self,
-                     GskRenderNode   *node,
-                     RenderOpBuilder *builder)
-{
-  GskRenderNode *child = gsk_opacity_node_get_child (node);
-  const float opacity = gsk_opacity_node_get_opacity (node);
-  float prev_opacity;
-
-  if (gsk_render_node_get_node_type (child) == GSK_CONTAINER_NODE)
-    {
-      gboolean is_offscreen;
-      TextureRegion region;
-
-      /* The semantics of an opacity node mandate that when, e.g., two color nodes overlap,
-       * there may not be any blending between them */
-      if (!add_offscreen_ops (self, builder, &child->bounds,
-                              child,
-                              &region, &is_offscreen,
-                              FORCE_OFFSCREEN | RESET_CLIP))
-        return;
-
-      prev_opacity = ops_set_opacity (builder,
-                                      builder->current_opacity * opacity);
-
-      if (builder->current_opacity >= ((float) 0x00ff / (float) 0xffff))
-        {
-          ops_set_program (builder, &self->programs->blit_program);
-          ops_set_texture (builder, region.texture_id);
-
-          load_vertex_data_with_region (ops_draw (builder, NULL),
-                                        &node->bounds, builder,
-                                        &region,
-                                        is_offscreen);
-        }
-    }
-  else
-    {
-      prev_opacity = ops_set_opacity (builder,
-                                      builder->current_opacity * opacity);
-
-      if (builder->current_opacity >= ((float) 0x00ff / (float) 0xffff))
-        gsk_gl_renderer_add_render_ops (self, child, builder);
-    }
-
-  ops_set_opacity (builder, prev_opacity);
-}
-
-static inline void
-render_linear_gradient_node (GskGLRenderer   *self,
-                             GskRenderNode   *node,
-                             RenderOpBuilder *builder)
-{
-  const int n_color_stops = gsk_linear_gradient_node_get_n_color_stops (node);
-
-  if (n_color_stops < GL_MAX_GRADIENT_STOPS)
-    {
-      const GskColorStop *stops = gsk_linear_gradient_node_get_color_stops (node, NULL);
-      const graphene_point_t *start = gsk_linear_gradient_node_get_start (node);
-      const graphene_point_t *end = gsk_linear_gradient_node_get_end (node);
-
-      ops_set_program (builder, &self->programs->linear_gradient_program);
-      ops_set_linear_gradient (builder,
-                               n_color_stops,
-                               stops,
-                               gsk_render_node_get_node_type (node) == GSK_REPEATING_LINEAR_GRADIENT_NODE,
-                               builder->dx + start->x,
-                               builder->dy + start->y,
-                               builder->dx + end->x,
-                               builder->dy + end->y);
-
-      load_vertex_data (ops_draw (builder, NULL), &node->bounds, builder);
-    }
-  else
-    {
-      render_fallback_node (self, node, builder);
-    }
-}
-
-static inline void
-render_radial_gradient_node (GskGLRenderer   *self,
-                             GskRenderNode   *node,
-                             RenderOpBuilder *builder)
-{
-  const int n_color_stops = gsk_radial_gradient_node_get_n_color_stops (node);
-
-  if (n_color_stops < GL_MAX_GRADIENT_STOPS)
-    {
-      const GskColorStop *stops = gsk_radial_gradient_node_get_color_stops (node, NULL);
-      const graphene_point_t *center = gsk_radial_gradient_node_get_center (node);
-      const float start = gsk_radial_gradient_node_get_start (node);
-      const float end = gsk_radial_gradient_node_get_end (node);
-      const float hradius = gsk_radial_gradient_node_get_hradius (node);
-      const float vradius = gsk_radial_gradient_node_get_vradius (node);
-
-      ops_set_program (builder, &self->programs->radial_gradient_program);
-      ops_set_radial_gradient (builder,
-                               n_color_stops,
-                               stops,
-                               gsk_render_node_get_node_type (node) == GSK_REPEATING_RADIAL_GRADIENT_NODE,
-                               builder->dx + center->x,
-                               builder->dy + center->y,
-                               start, end,
-                               hradius * builder->scale_x,
-                               vradius * builder->scale_y);
-
-      load_vertex_data (ops_draw (builder, NULL), &node->bounds, builder);
-    }
-  else
-    {
-      render_fallback_node (self, node, builder);
-    }
-}
-
-static inline void
-render_conic_gradient_node (GskGLRenderer   *self,
-                             GskRenderNode   *node,
-                             RenderOpBuilder *builder)
-{
-  const int n_color_stops = gsk_conic_gradient_node_get_n_color_stops (node);
-
-  if (n_color_stops < GL_MAX_GRADIENT_STOPS)
-    {
-      const GskColorStop *stops = gsk_conic_gradient_node_get_color_stops (node, NULL);
-      const graphene_point_t *center = gsk_conic_gradient_node_get_center (node);
-      const float angle = gsk_conic_gradient_node_get_angle (node);
-
-      ops_set_program (builder, &self->programs->conic_gradient_program);
-      ops_set_conic_gradient (builder,
-                              n_color_stops,
-                              stops,
-                              builder->dx + center->x,
-                              builder->dy + center->y,
-                              angle);
-
-      load_vertex_data (ops_draw (builder, NULL), &node->bounds, builder);
-    }
-  else
-    {
-      render_fallback_node (self, node, builder);
-    }
-}
-
-static inline gboolean
-rounded_inner_rect_contains_rect (const GskRoundedRect  *rounded,
-                                  const graphene_rect_t *rect)
-{
-  const graphene_rect_t *rounded_bounds = &rounded->bounds;
-  graphene_rect_t inner;
-  float offset_x, offset_y;
-
-  /* TODO: This is pretty conservative and we could to further, more
-   *       fine-grained checks to avoid offscreen drawing. */
-
-  offset_x = MAX (rounded->corner[GSK_CORNER_TOP_LEFT].width,
-                  rounded->corner[GSK_CORNER_BOTTOM_LEFT].width);
-  offset_y = MAX (rounded->corner[GSK_CORNER_TOP_LEFT].height,
-                  rounded->corner[GSK_CORNER_TOP_RIGHT].height);
-
-
-  inner.origin.x = rounded_bounds->origin.x + offset_x;
-  inner.origin.y = rounded_bounds->origin.y + offset_y;
-  inner.size.width = rounded_bounds->size.width - offset_x -
-                     MAX (rounded->corner[GSK_CORNER_TOP_RIGHT].width,
-                          rounded->corner[GSK_CORNER_BOTTOM_RIGHT].width);
-  inner.size.height = rounded_bounds->size.height - offset_y -
-                      MAX (rounded->corner[GSK_CORNER_BOTTOM_LEFT].height,
-                           rounded->corner[GSK_CORNER_BOTTOM_RIGHT].height);
-
-  return _graphene_rect_contains_rect (&inner, rect);
-}
-
-/* Current clip is NOT rounded but new one is definitely! */
-static inline bool
-intersect_rounded_rectilinear (const graphene_rect_t *non_rounded,
-                               const GskRoundedRect  *rounded,
-                               GskRoundedRect        *result)
-{
-  bool corners[4];
-
-  /* Intersects with top left corner? */
-  corners[0] = rounded_rect_has_corner (rounded, 0) &&
-               graphene_rect_intersects (non_rounded,
-                                         &rounded_rect_corner (rounded, 0));
-  /* top right? */
-  corners[1] = rounded_rect_has_corner (rounded, 1) &&
-               graphene_rect_intersects (non_rounded,
-                                         &rounded_rect_corner (rounded, 1));
-  /* bottom right? */
-  corners[2] = rounded_rect_has_corner (rounded, 2) &&
-               graphene_rect_intersects (non_rounded,
-                                         &rounded_rect_corner (rounded, 2));
-  /* bottom left */
-  corners[3] = rounded_rect_has_corner (rounded, 3) &&
-               graphene_rect_intersects (non_rounded,
-                                         &rounded_rect_corner (rounded, 3));
-
-  if (corners[0] && !_graphene_rect_contains_rect (non_rounded, &rounded_rect_corner (rounded, 0)))
-    return false;
-  if (corners[1] && !_graphene_rect_contains_rect (non_rounded, &rounded_rect_corner (rounded, 1)))
-    return false;
-  if (corners[2] && !_graphene_rect_contains_rect (non_rounded, &rounded_rect_corner (rounded, 2)))
-    return false;
-  if (corners[3] && !_graphene_rect_contains_rect (non_rounded, &rounded_rect_corner (rounded, 3)))
-    return false;
-
-  /* We do intersect with at least one of the corners, but in such a way that the
-   * intersection between the two clips can still be represented by a single rounded
-   * rect in a trivial way. do that. */
-  graphene_rect_intersection (non_rounded, &rounded->bounds, &result->bounds);
-
-  for (int i = 0; i < 4; i++)
-    {
-      if (corners[i])
-        result->corner[i] = rounded->corner[i];
-      else
-        result->corner[i].width = result->corner[i].height = 0;
-    }
-
-  return true;
-}
-
-/* This code intersects the current (maybe rounded) clip with the new
- * non-rounded clip */
-static inline void
-render_clipped_child (GskGLRenderer         *self,
-                      RenderOpBuilder       *builder,
-                      const graphene_rect_t *clip,
-                      GskRenderNode         *child)
-{
-  graphene_rect_t transformed_clip;
-  GskRoundedRect intersection;
-
-  ops_transform_bounds_modelview (builder, clip, &transformed_clip);
-
-  if (builder->clip_is_rectilinear)
-    {
-      memset (&intersection, 0, sizeof (GskRoundedRect));
-      graphene_rect_intersection (&transformed_clip,
-                                  &builder->current_clip->bounds,
-                                  &intersection.bounds);
-
-      ops_push_clip (builder, &intersection);
-      gsk_gl_renderer_add_render_ops (self, child, builder);
-      ops_pop_clip (builder);
-    }
-  else if (intersect_rounded_rectilinear (&transformed_clip,
-                                          builder->current_clip,
-                                          &intersection))
-    {
-      ops_push_clip (builder, &intersection);
-      gsk_gl_renderer_add_render_ops (self, child, builder);
-      ops_pop_clip (builder);
-    }
-  else
-    {
-      /* well fuck */
-      const float scale_x = builder->scale_x;
-      const float scale_y = builder->scale_y;
-      const GskRoundedRect scaled_clip = GSK_ROUNDED_RECT_INIT ((builder->dx + clip->origin.x) * scale_x,
-                                                                (builder->dy + clip->origin.y) * scale_y,
-                                                                clip->size.width * scale_x,
-                                                                clip->size.height * scale_y);
-      gboolean is_offscreen;
-      TextureRegion region;
-
-      ops_push_clip (builder, &scaled_clip);
-      if (!add_offscreen_ops (self, builder, &child->bounds,
-                              child,
-                              &region, &is_offscreen,
-                              FORCE_OFFSCREEN))
-        g_assert_not_reached ();
-      ops_pop_clip (builder);
-
-      ops_set_program (builder, &self->programs->blit_program);
-      ops_set_texture (builder, region.texture_id);
-
-      load_offscreen_vertex_data (ops_draw (builder, NULL), child, builder);
-    }
-}
-
-static inline void
-render_clip_node (GskGLRenderer   *self,
-                  GskRenderNode   *node,
-                  RenderOpBuilder *builder)
-{
-  const graphene_rect_t *clip = gsk_clip_node_get_clip (node);
-  GskRenderNode *child = gsk_clip_node_get_child (node);
-
-  render_clipped_child (self, builder, clip, child);
-}
-
-static inline void
-render_rounded_clip_node (GskGLRenderer       *self,
-                          GskRenderNode       *node,
-                          RenderOpBuilder     *builder)
-{
-  const float scale_x = builder->scale_x;
-  const float scale_y = builder->scale_y;
-  const GskRoundedRect *clip = gsk_rounded_clip_node_get_clip (node);
-  GskRenderNode *child = gsk_rounded_clip_node_get_child (node);
-  GskRoundedRect transformed_clip;
-  gboolean need_offscreen;
-  int i;
-
-  if (node_is_invisible (child))
-    return;
-
-  ops_transform_bounds_modelview (builder, &clip->bounds, &transformed_clip.bounds);
-  for (i = 0; i < 4; i ++)
-    {
-      transformed_clip.corner[i].width = clip->corner[i].width * scale_x;
-      transformed_clip.corner[i].height = clip->corner[i].height * scale_y;
-    }
-
-  if (builder->clip_is_rectilinear)
-    {
-      GskRoundedRect intersected_clip;
-
-      if (intersect_rounded_rectilinear (&builder->current_clip->bounds,
-                                         &transformed_clip,
-                                         &intersected_clip))
-        {
-          ops_push_clip (builder, &intersected_clip);
-          gsk_gl_renderer_add_render_ops (self, child, builder);
-          ops_pop_clip (builder);
-          return;
-        }
-    }
-
-  /* After this point we are really working with a new and a current clip
-   * which both have rounded corners. */
-
-  if (!ops_has_clip (builder))
-    need_offscreen = FALSE;
-  else if (rounded_inner_rect_contains_rect (builder->current_clip,
-                                             &transformed_clip.bounds))
-    need_offscreen = FALSE;
-  else
-    need_offscreen = TRUE;
-
-  if (!need_offscreen)
-    {
-      /* If they don't intersect at all, we can simply set
-       * the new clip and add the render ops */
-
-      /* If the new clip entirely contains the current clip, the intersection is simply
-       * the current clip, so we can ignore the new one */
-      if (rounded_inner_rect_contains_rect (&transformed_clip, &builder->current_clip->bounds))
-        {
-          gsk_gl_renderer_add_render_ops (self, child, builder);
-          return;
-        }
-
-      ops_push_clip (builder, &transformed_clip);
-      gsk_gl_renderer_add_render_ops (self, child, builder);
-      ops_pop_clip (builder);
-    }
-  else
-    {
-      gboolean is_offscreen;
-      TextureRegion region;
-
-      ops_push_clip (builder, &transformed_clip);
-      if (!add_offscreen_ops (self, builder, &node->bounds,
-                              child,
-                              &region, &is_offscreen,
-                              FORCE_OFFSCREEN))
-        g_assert_not_reached ();
-      ops_pop_clip (builder);
-
-      ops_set_program (builder, &self->programs->blit_program);
-      ops_set_texture (builder, region.texture_id);
-
-      load_vertex_data_with_region (ops_draw (builder, NULL), &node->bounds, builder,
-                                    &region, is_offscreen);
-    }
-}
-
-static inline void
-render_color_matrix_node (GskGLRenderer       *self,
-                          GskRenderNode       *node,
-                          RenderOpBuilder     *builder)
-{
-  GskRenderNode *child = gsk_color_matrix_node_get_child (node);
-  TextureRegion region;
-  gboolean is_offscreen;
-
-  if (node_is_invisible (child))
-    return;
-
-  if (!add_offscreen_ops (self, builder,
-                          &node->bounds,
-                          child,
-                          &region, &is_offscreen,
-                          RESET_CLIP))
-    g_assert_not_reached ();
-
-  ops_set_program (builder, &self->programs->color_matrix_program);
-  ops_set_color_matrix (builder,
-                        gsk_color_matrix_node_get_color_matrix (node),
-                        gsk_color_matrix_node_get_color_offset (node));
-
-  ops_set_texture (builder, region.texture_id);
-
-  load_vertex_data_with_region (ops_draw (builder, NULL),
-                                &node->bounds, builder,
-                                &region,
-                                is_offscreen);
-}
-
-static inline int
-blur_texture (GskGLRenderer       *self,
-              RenderOpBuilder     *builder,
-              const TextureRegion *region,
-              const int            texture_to_blur_width,
-              const int            texture_to_blur_height,
-              float                blur_radius_x,
-              float                blur_radius_y)
-{
-  const GskRoundedRect new_clip = GSK_ROUNDED_RECT_INIT (0, 0, texture_to_blur_width, texture_to_blur_height);
-  int pass1_texture_id, pass1_render_target;
-  int pass2_texture_id, pass2_render_target;
-  int prev_render_target;
-  graphene_matrix_t prev_projection;
-  graphene_rect_t prev_viewport;
-  graphene_matrix_t item_proj;
-  OpBlur *op;
-
-  g_assert (blur_radius_x > 0);
-  g_assert (blur_radius_y > 0);
-
-  gsk_gl_driver_create_render_target (self->gl_driver,
-                                      MAX (texture_to_blur_width, 1), MAX (texture_to_blur_height, 1),
-                                      GL_NEAREST, GL_NEAREST,
-                                      &pass1_texture_id, &pass1_render_target);
-
-  if (texture_to_blur_width <= 0 || texture_to_blur_height <= 0)
-    {
-      return pass1_texture_id;
-    }
-
-  gsk_gl_driver_create_render_target (self->gl_driver,
-                                      texture_to_blur_width, texture_to_blur_height,
-                                      GL_NEAREST, GL_NEAREST,
-                                      &pass2_texture_id, &pass2_render_target);
-
-  init_projection_matrix (&item_proj, &new_clip.bounds);
-
-  ops_set_program (builder, &self->programs->blur_program);
-  prev_projection = ops_set_projection (builder, &item_proj);
-  ops_set_modelview (builder, NULL);
-  prev_viewport = ops_set_viewport (builder, &new_clip.bounds);
-  ops_push_clip (builder, &new_clip);
-
-  prev_render_target = ops_set_render_target (builder, pass1_render_target);
-  ops_begin (builder, OP_CLEAR);
-
-  op = ops_begin (builder, OP_CHANGE_BLUR);
-  op->size.width = texture_to_blur_width;
-  op->size.height = texture_to_blur_height;
-  op->radius = blur_radius_x;
-  op->dir[0] = 1;
-  op->dir[1] = 0;
-  ops_set_texture (builder, region->texture_id);
-
-  load_vertex_data_with_region (ops_draw (builder, NULL),
-                                &new_clip.bounds,
-                                builder, region,
-                                FALSE);
-#if 0
-  {
-    static int k;
-    ops_dump_framebuffer (builder,
-                          g_strdup_printf ("pass1_%d.png", k++),
-                          texture_to_blur_width,
-                          texture_to_blur_height);
-  }
-#endif
-  op = ops_begin (builder, OP_CHANGE_BLUR);
-  op->size.width = texture_to_blur_width;
-  op->size.height = texture_to_blur_height;
-  op->radius = blur_radius_y;
-  op->dir[0] = 0;
-  op->dir[1] = 1;
-  ops_set_texture (builder, pass1_texture_id);
-  ops_set_render_target (builder, pass2_render_target);
-  ops_begin (builder, OP_CLEAR);
-  load_vertex_data_with_region (ops_draw (builder, NULL), /* render pass 2 */
-                                &new_clip.bounds,
-                                builder, region,
-                                FALSE);
-
-#if 0
-  {
-    static int k;
-    ops_dump_framebuffer (builder,
-                          g_strdup_printf ("blurred%d.png", k++),
-                          texture_to_blur_width,
-                          texture_to_blur_height);
-  }
-#endif
-
-  ops_set_render_target (builder, prev_render_target);
-  ops_set_viewport (builder, &prev_viewport);
-  ops_set_projection (builder, &prev_projection);
-  ops_pop_modelview (builder);
-  ops_pop_clip (builder);
-
-  return pass2_texture_id;
-}
-
-static inline void
-blur_node (GskGLRenderer   *self,
-           GskRenderNode   *node,
-           RenderOpBuilder *builder,
-           float            blur_radius,
-           guint            extra_flags,
-           TextureRegion   *out_region,
-           float           *out_vertex_data[4]) /* min, max, min, max */
-{
-  const float scale_x = builder->scale_x;
-  const float scale_y = builder->scale_y;
-  const float blur_extra = blur_radius * 2.0; /* 2.0 = shader radius_multiplier */
-  float texture_width, texture_height;
-  gboolean is_offscreen;
-  TextureRegion region;
-  int blurred_texture_id;
-
-  g_assert (blur_radius > 0);
-
-  /* Increase texture size for the given blur radius and scale it */
-  texture_width  = ceilf ((node->bounds.size.width  + blur_extra));
-  texture_height = ceilf ((node->bounds.size.height + blur_extra));
-
-  /* Only blur this if the out region has no texture id yet */
-  if (out_region->texture_id == 0)
-    {
-      if (!add_offscreen_ops (self, builder,
-                              &GRAPHENE_RECT_INIT (node->bounds.origin.x - (blur_extra / 2.0),
-                                                   node->bounds.origin.y - (blur_extra / 2.0),
-                                                   texture_width, texture_height),
-                              node,
-                              &region, &is_offscreen,
-                              RESET_CLIP | FORCE_OFFSCREEN | extra_flags))
-        g_assert_not_reached ();
-
-      blurred_texture_id = blur_texture (self, builder,
-                                         &region,
-                                         texture_width * scale_x, texture_height * scale_y,
-                                         blur_radius * scale_x,
-                                         blur_radius * scale_y);
-      init_full_texture_region (out_region, blurred_texture_id);
-    }
-
-  if (out_vertex_data)
-    {
-      *out_vertex_data[0] = builder->dx + node->bounds.origin.x - (blur_extra / 2.0);
-      *out_vertex_data[1] = builder->dx + node->bounds.origin.x + node->bounds.size.width + (blur_extra / 2.0);
-      *out_vertex_data[2] = builder->dy + node->bounds.origin.y - (blur_extra / 2.0);
-      *out_vertex_data[3] = builder->dy + node->bounds.origin.y + node->bounds.size.height + (blur_extra / 2.0);
-    }
-}
-
-static inline void
-render_blur_node (GskGLRenderer   *self,
-                  GskRenderNode   *node,
-                  RenderOpBuilder *builder)
-{
-  const float blur_radius = gsk_blur_node_get_radius (node);
-  GskRenderNode *child = gsk_blur_node_get_child (node);
-  TextureRegion blurred_region;
-  GskTextureKey key;
-  float min_x, max_x, min_y, max_y;
-
-  if (node_is_invisible (child))
-    return;
-
-  if (blur_radius <= 0)
-    {
-      gsk_gl_renderer_add_render_ops (self, child, builder);
-      return;
-    }
-
-  key.pointer = node;
-  key.pointer_is_child = FALSE;
-  key.scale_x = builder->scale_x;
-  key.scale_y = builder->scale_y;
-  key.filter = GL_NEAREST;
-  blurred_region.texture_id = gsk_gl_driver_get_texture_for_key (self->gl_driver, &key);
-  blur_node (self, child, builder, blur_radius, 0, &blurred_region,
-             (float*[4]){&min_x, &max_x, &min_y, &max_y});
-
-  g_assert (blurred_region.texture_id != 0);
-
-  /* Draw the result */
-  ops_set_program (builder, &self->programs->blit_program);
-  ops_set_texture (builder, blurred_region.texture_id);
-  fill_vertex_data (ops_draw (builder, NULL), min_x, min_y, max_x, max_y);
-
-
-  /* Add to cache for the blur node */
-  gsk_gl_driver_set_texture_for_key (self->gl_driver, &key, blurred_region.texture_id);
-}
-
-static inline void
-render_unblurred_inset_shadow_node (GskGLRenderer   *self,
-                                    GskRenderNode   *node,
-                                    RenderOpBuilder *builder)
-{
-  const float dx = gsk_inset_shadow_node_get_dx (node);
-  const float dy = gsk_inset_shadow_node_get_dy (node);
-  const float spread = gsk_inset_shadow_node_get_spread (node);
-
-  g_assert (gsk_inset_shadow_node_get_blur_radius (node) == 0);
-
-  ops_set_program (builder, &self->programs->inset_shadow_program);
-  ops_set_inset_shadow (builder, transform_rect (self, builder, gsk_inset_shadow_node_get_outline (node)),
-                        spread,
-                        gsk_inset_shadow_node_get_color (node),
-                        dx, dy);
-
-  load_vertex_data (ops_draw (builder, NULL), &node->bounds, builder);
-}
-
-static inline void
-render_inset_shadow_node (GskGLRenderer   *self,
-                          GskRenderNode   *node,
-                          RenderOpBuilder *builder)
-{
-  const float scale_x = builder->scale_x;
-  const float scale_y = builder->scale_y;
-  const float blur_radius = gsk_inset_shadow_node_get_blur_radius (node);
-  const float blur_extra = blur_radius * 2.0; /* 2.0 = shader radius_multiplier */
-  const float dx = gsk_inset_shadow_node_get_dx (node);
-  const float dy = gsk_inset_shadow_node_get_dy (node);
-  const GskRoundedRect *node_outline = gsk_inset_shadow_node_get_outline (node);
-  float texture_width;
-  float texture_height;
-  int blurred_texture_id;
-  GskTextureKey key;
-
-  g_assert (blur_radius > 0);
-
-  texture_width = ceilf ((node_outline->bounds.size.width + blur_extra) * scale_x);
-  texture_height = ceilf ((node_outline->bounds.size.height + blur_extra) * scale_y);
-
-  key.pointer = node;
-  key.pointer_is_child = FALSE;
-  key.scale_x = scale_x;
-  key.scale_y = scale_y;
-  key.filter = GL_NEAREST;
-  blurred_texture_id = gsk_gl_driver_get_texture_for_key (self->gl_driver, &key);
-  if (blurred_texture_id == 0)
-    {
-      const float spread = gsk_inset_shadow_node_get_spread (node) + (blur_extra / 2.0);
-      GskRoundedRect outline_to_blur;
-      int render_target, texture_id;
-      int prev_render_target;
-      graphene_matrix_t prev_projection;
-      graphene_rect_t prev_viewport;
-      graphene_matrix_t item_proj;
-      int i;
-
-      /* TODO: In the following code, we have to be careful about where we apply the scale.
-       * We're manually scaling stuff (e.g. the outline) so we can later use texture_width
-       * and texture_height (which are already scaled) as the geometry and keep the modelview
-       * at a scale of 1. That's kinda complicated though... */
-
-      /* Outline of what we actually want to blur later.
-       * Spread grows inside, so we don't need to account for that. But the blur will need
-       * to read outside of the inset shadow, so we need to draw some color in there. */
-      outline_to_blur = *node_outline;
-      gsk_rounded_rect_shrink (&outline_to_blur,
-                               - blur_extra / 2.0, - blur_extra / 2.0,
-                               - blur_extra / 2.0, - blur_extra / 2.0);
-
-      /* Fit to our texture */
-      outline_to_blur.bounds.origin.x = 0;
-      outline_to_blur.bounds.origin.y = 0;
-      outline_to_blur.bounds.size.width *= scale_x;
-      outline_to_blur.bounds.size.height *= scale_y;
-
-      for (i = 0; i < 4; i ++)
-        {
-          outline_to_blur.corner[i].width *= scale_x;
-          outline_to_blur.corner[i].height *= scale_y;
-        }
-
-      gsk_gl_driver_create_render_target (self->gl_driver,
-                                          texture_width, texture_height,
-                                          GL_NEAREST, GL_NEAREST,
-                                          &texture_id, &render_target);
-
-      init_projection_matrix (&item_proj,
-                              &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height));
-
-      prev_projection = ops_set_projection (builder, &item_proj);
-      ops_set_modelview (builder, NULL);
-      prev_viewport = ops_set_viewport (builder, &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height));
-      ops_push_clip (builder, &GSK_ROUNDED_RECT_INIT (0, 0, texture_width, texture_height));
-
-      prev_render_target = ops_set_render_target (builder, render_target);
-      ops_begin (builder, OP_CLEAR);
-
-      /* Actual inset shadow outline drawing */
-      ops_set_program (builder, &self->programs->inset_shadow_program);
-      ops_set_inset_shadow (builder, transform_rect (self, builder, &outline_to_blur),
-                            spread * MAX (scale_x, scale_y),
-                            gsk_inset_shadow_node_get_color (node),
-                            dx * scale_x, dy * scale_y);
-
-      load_float_vertex_data (ops_draw (builder, NULL), builder,
-                              0, 0, texture_width, texture_height);
-
-      ops_set_render_target (builder, prev_render_target);
-      ops_set_viewport (builder, &prev_viewport);
-      ops_set_projection (builder, &prev_projection);
-      ops_pop_modelview (builder);
-      ops_pop_clip (builder);
-
-      blurred_texture_id = blur_texture (self, builder,
-                                         &(TextureRegion) { texture_id, 0, 0, 1, 1 },
-                                         texture_width,
-                                         texture_height,
-                                         blur_radius * scale_x,
-                                         blur_radius * scale_y);
-    }
-
-  g_assert (blurred_texture_id != 0);
-
-  /* Blur the rendered unblurred inset shadow */
-  /* Use a clip to cut away the unwanted parts outside of the original outline */
-  {
-    const gboolean needs_clip = !gsk_rounded_rect_is_rectilinear (node_outline);
-    const float tx1 = blur_extra / 2.0 * scale_x / texture_width;
-    const float tx2 = 1.0 - tx1;
-    const float ty1 = blur_extra / 2.0 * scale_y / texture_height;
-    const float ty2 = 1.0 - ty1;
-
-    gsk_gl_driver_set_texture_for_key (self->gl_driver, &key, blurred_texture_id);
-
-    if (needs_clip)
-      {
-        GskRoundedRect node_clip;
-
-        ops_transform_bounds_modelview (builder, &node_outline->bounds, &node_clip.bounds);
-        for (int i = 0; i < 4; i ++)
-          {
-            node_clip.corner[i].width = node_outline->corner[i].width * scale_x;
-            node_clip.corner[i].height = node_outline->corner[i].height * scale_y;
-          }
-
-        ops_push_clip (builder, &node_clip);
-      }
-
-    ops_set_program (builder, &self->programs->blit_program);
-    ops_set_texture (builder, blurred_texture_id);
-
-    load_vertex_data_with_region (ops_draw (builder, NULL),
-                                  &node->bounds, builder,
-                                  &(TextureRegion) { 0, tx1, ty1, tx2, ty2 },
-                                  TRUE);
-
-    if (needs_clip)
-      ops_pop_clip (builder);
-  }
-
-}
-
-/* Spread *grows* the outline. The offset moves the shadow and leaves the
- * inner rect where it was */
-static inline void
-render_unblurred_outset_shadow_node (GskGLRenderer   *self,
-                                     GskRenderNode   *node,
-                                     RenderOpBuilder *builder)
-{
-  const GskRoundedRect *outline = gsk_outset_shadow_node_get_outline (node);
-  const float x = node->bounds.origin.x;
-  const float y = node->bounds.origin.y;
-  const float w = node->bounds.size.width;
-  const float h = node->bounds.size.height;
-  const float spread = gsk_outset_shadow_node_get_spread (node);
-  const float dx = gsk_outset_shadow_node_get_dx (node);
-  const float dy = gsk_outset_shadow_node_get_dy (node);
-  const float edge_sizes[] = { // Top, right, bottom, left
-    spread - dy, spread + dx, spread + dy, spread - dx
-  };
-  const float corner_sizes[][2] = { // top left, top right, bottom right, bottom left
-    { outline->corner[0].width + spread - dx, outline->corner[0].height + spread - dy },
-    { outline->corner[1].width + spread + dx, outline->corner[1].height + spread - dy },
-    { outline->corner[2].width + spread + dx, outline->corner[2].height + spread + dy },
-    { outline->corner[3].width + spread - dx, outline->corner[3].height + spread + dy },
-  };
-
-  ops_set_program (builder, &self->programs->unblurred_outset_shadow_program);
-  ops_set_unblurred_outset_shadow (builder, transform_rect (self, builder, outline),
-                                   spread,
-                                   gsk_outset_shadow_node_get_color (node),
-                                   dx, dy);
-
-  /* Corners... */
-  if (corner_sizes[0][0] > 0 && corner_sizes[0][1] > 0) /* Top left */
-      load_float_vertex_data (ops_draw (builder, NULL), builder,
-                              x, y,
-                              corner_sizes[0][0], corner_sizes[0][1]);
-  if (corner_sizes[1][0] > 0 && corner_sizes[1][1] > 0) /* Top right */
-      load_float_vertex_data (ops_draw (builder, NULL), builder,
-                              x + w - corner_sizes[1][0], y,
-                              corner_sizes[1][0], corner_sizes[1][1]);
-  if (corner_sizes[2][0] > 0 && corner_sizes[2][1] > 0) /* Bottom right */
-      load_float_vertex_data (ops_draw (builder, NULL), builder,
-                              x + w - corner_sizes[2][0], y + h - corner_sizes[2][1],
-                              corner_sizes[2][0], corner_sizes[2][1]);
-  if (corner_sizes[3][0] > 0 && corner_sizes[3][1] > 0) /* Bottom left */
-      load_float_vertex_data (ops_draw (builder, NULL), builder,
-                              x, y + h - corner_sizes[3][1],
-                              corner_sizes[3][0], corner_sizes[3][1]);
-  /* Edges... */;
-  if (edge_sizes[0] > 0) /* Top */
-    load_float_vertex_data (ops_draw (builder, NULL), builder,
-                            x + corner_sizes[0][0], y,
-                            w - corner_sizes[0][0] - corner_sizes[1][0], edge_sizes[0]);
-  if (edge_sizes[1] > 0) /* Right */
-    load_float_vertex_data (ops_draw (builder, NULL), builder,
-                            x + w - edge_sizes[1], y + corner_sizes[1][1],
-                            edge_sizes[1], h - corner_sizes[1][1] - corner_sizes[2][1]);
-  if (edge_sizes[2] > 0) /* Bottom */
-    load_float_vertex_data (ops_draw (builder, NULL), builder,
-                            x + corner_sizes[3][0], y + h - edge_sizes[2],
-                            w - corner_sizes[3][0] - corner_sizes[2][0], edge_sizes[2]);
-  if (edge_sizes[3] > 0) /* Left */
-    load_float_vertex_data (ops_draw (builder, NULL), builder,
-                            x, y + corner_sizes[0][1],
-                            edge_sizes[3], h - corner_sizes[0][1] - corner_sizes[3][1]);
-}
-
-
-static GdkRGBA COLOR_WHITE = { 1, 1, 1, 1 };
-static inline void
-render_outset_shadow_node (GskGLRenderer   *self,
-                           GskRenderNode   *node,
-                           RenderOpBuilder *builder)
-{
-  const float scale_x = builder->scale_x;
-  const float scale_y = builder->scale_y;
-  const GskRoundedRect *outline = gsk_outset_shadow_node_get_outline (node);
-  const GdkRGBA *color = gsk_outset_shadow_node_get_color (node);
-  const float blur_radius = gsk_outset_shadow_node_get_blur_radius (node);
-  const float blur_extra = blur_radius * 2.0f; /* 2.0 = shader radius_multiplier */
-  const int extra_blur_pixels = (int) ceilf(blur_extra / 2.0 * MAX (scale_x, scale_y)); /* TODO: No need to MAX() her actually */
-  const float spread = gsk_outset_shadow_node_get_spread (node);
-  const float dx = gsk_outset_shadow_node_get_dx (node);
-  const float dy = gsk_outset_shadow_node_get_dy (node);
-  GskRoundedRect scaled_outline;
-  int texture_width, texture_height;
-  OpOutsetShadow *shadow;
-  int blurred_texture_id;
-  int cached_tid;
-  bool do_slicing;
-
-  /* scaled_outline is the minimal outline we need to draw the given drop shadow,
-   * enlarged by the spread and offset by the blur radius. */
-  scaled_outline = *outline;
-
-  if (outline->bounds.size.width < blur_extra ||
-      outline->bounds.size.height < blur_extra)
-    {
-      do_slicing = false;
-      gsk_rounded_rect_shrink (&scaled_outline, -spread, -spread, -spread, -spread);
-    }
-  else
-    {
-      /* Shrink our outline to the minimum size that can still hold all the border radii */
-      gsk_rounded_rect_shrink_to_minimum (&scaled_outline);
-      /* Increase by the spread */
-      gsk_rounded_rect_shrink (&scaled_outline, -spread, -spread, -spread, -spread);
-      /* Grow bounds but don't grow corners */
-      graphene_rect_inset (&scaled_outline.bounds, - blur_extra / 2.0, - blur_extra / 2.0);
-      /* For the center part, we add a few pixels */
-      scaled_outline.bounds.size.width += SHADOW_EXTRA_SIZE;
-      scaled_outline.bounds.size.height += SHADOW_EXTRA_SIZE;
-
-      do_slicing = true;
-    }
-
-  texture_width  = (int)ceil ((scaled_outline.bounds.size.width  + blur_extra) * scale_x);
-  texture_height = (int)ceil ((scaled_outline.bounds.size.height + blur_extra) * scale_y);
-
-  scaled_outline.bounds.origin.x = extra_blur_pixels;
-  scaled_outline.bounds.origin.y = extra_blur_pixels;
-  scaled_outline.bounds.size.width = texture_width - (extra_blur_pixels * 2);
-  scaled_outline.bounds.size.height = texture_height - (extra_blur_pixels * 2);
-
-  for (int i = 0; i < 4; i ++)
-    {
-      scaled_outline.corner[i].width *= scale_x;
-      scaled_outline.corner[i].height *= scale_y;
-    }
-
-  cached_tid = gsk_gl_shadow_cache_get_texture_id (&self->shadow_cache,
-                                                   self->gl_driver,
-                                                   &scaled_outline,
-                                                   blur_radius);
-
-  if (cached_tid == 0)
-    {
-      int texture_id, render_target;
-      int prev_render_target;
-      graphene_matrix_t prev_projection;
-      graphene_rect_t prev_viewport;
-      graphene_matrix_t item_proj;
-
-      gsk_gl_driver_create_render_target (self->gl_driver,
-                                          texture_width, texture_height,
-                                          GL_NEAREST, GL_NEAREST,
-                                          &texture_id, &render_target);
-      if (gdk_gl_context_has_debug (self->gl_context))
-        {
-          gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, texture_id,
-                                              "Outset Shadow Temp %d", texture_id);
-          gdk_gl_context_label_object_printf  (self->gl_context, GL_FRAMEBUFFER, render_target,
-                                               "Outset Shadow FB Temp %d", render_target);
-        }
-
-      ops_set_program (builder, &self->programs->color_program);
-      init_projection_matrix (&item_proj,
-                              &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height));
-
-      prev_render_target = ops_set_render_target (builder, render_target);
-      ops_begin (builder, OP_CLEAR);
-      prev_projection = ops_set_projection (builder, &item_proj);
-      ops_set_modelview (builder, NULL);
-      prev_viewport = ops_set_viewport (builder, &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height));
-
-      /* Draw outline */
-      ops_push_clip (builder, &scaled_outline);
-      ops_set_color (builder, &COLOR_WHITE);
-      load_float_vertex_data (ops_draw (builder, NULL), builder,
-                              0, 0, texture_width, texture_height);
-
-      ops_pop_clip (builder);
-      ops_set_viewport (builder, &prev_viewport);
-      ops_pop_modelview (builder);
-      ops_set_projection (builder, &prev_projection);
-      ops_set_render_target (builder, prev_render_target);
-
-      /* Now blur the outline */
-      blurred_texture_id = blur_texture (self, builder,
-                                         &(TextureRegion) { texture_id, 0, 0, 1, 1 },
-                                         texture_width,
-                                         texture_height,
-                                         blur_radius * scale_x,
-                                         blur_radius * scale_y);
-
-      gsk_gl_driver_mark_texture_permanent (self->gl_driver, blurred_texture_id);
-      gsk_gl_shadow_cache_commit (&self->shadow_cache,
-                                  &scaled_outline,
-                                  blur_radius,
-                                  blurred_texture_id);
-    }
-  else
-    {
-      blurred_texture_id = cached_tid;
-    }
-
-
-  if (!do_slicing)
-    {
-      const float min_x = floorf (outline->bounds.origin.x - spread - (blur_extra / 2.0) + dx);
-      const float min_y = floorf (outline->bounds.origin.y - spread - (blur_extra / 2.0) + dy);
-
-      ops_set_program (builder, &self->programs->outset_shadow_program);
-      ops_set_color (builder, color);
-      ops_set_texture (builder, blurred_texture_id);
-
-      shadow = ops_begin (builder, OP_CHANGE_OUTSET_SHADOW);
-      shadow->outline.value = transform_rect (self, builder, outline);
-      shadow->outline.send = TRUE;
-
-      load_vertex_data_with_region (ops_draw (builder, NULL),
-                                    &GRAPHENE_RECT_INIT (
-                                      min_x, min_y,
-                                      texture_width / scale_x, texture_height / scale_y
-                                    ), builder,
-                                    &(TextureRegion) { 0, 0, 0, 1, 1 },
-                                    FALSE);
-      return;
-    }
-
-
-  ops_set_program (builder, &self->programs->outset_shadow_program);
-  ops_set_color (builder, color);
-  ops_set_texture (builder, blurred_texture_id);
-
-  shadow = ops_begin (builder, OP_CHANGE_OUTSET_SHADOW);
-  shadow->outline.value = transform_rect (self, builder, outline);
-  shadow->outline.send = TRUE;
-
-  {
-    const float min_x = floorf (outline->bounds.origin.x - spread - (blur_extra / 2.0) + dx);
-    const float min_y = floorf (outline->bounds.origin.y - spread - (blur_extra / 2.0) + dy);
-    const float max_x = ceilf (outline->bounds.origin.x + outline->bounds.size.width +
-                               (blur_extra / 2.0) + dx + spread);
-    const float max_y = ceilf (outline->bounds.origin.y + outline->bounds.size.height +
-                               (blur_extra / 2.0) + dy + spread);
-    cairo_rectangle_int_t slices[9];
-    TextureRegion tregs[9];
-
-    /* TODO: The slicing never changes and could just go into the cache */
-    nine_slice_rounded_rect (&scaled_outline, slices);
-    nine_slice_grow (slices, extra_blur_pixels);
-    nine_slice_to_texture_coords (slices, texture_width, texture_height, tregs);
-
-    /* Our texture coordinates MUST be scaled, while the actual vertex coords
-     * MUST NOT be scaled. */
-
-    /* Top left */
-    if (slice_is_visible (&slices[NINE_SLICE_TOP_LEFT]))
-      {
-        load_vertex_data_with_region (ops_draw (builder, NULL),
-                                      &GRAPHENE_RECT_INIT (
-                                        min_x, min_y,
-                                        slices[NINE_SLICE_TOP_LEFT].width / scale_x,
-                                        slices[NINE_SLICE_TOP_LEFT].height / scale_y
-                                      ),
-                                      builder,
-                                      &tregs[NINE_SLICE_TOP_LEFT], TRUE);
-      }
-
-    /* Top center */
-    if (slice_is_visible (&slices[NINE_SLICE_TOP_CENTER]))
-      {
-        const float width = (max_x - min_x) - (slices[NINE_SLICE_TOP_LEFT].width / scale_x +
-                                               slices[NINE_SLICE_TOP_RIGHT].width / scale_x);
-        load_vertex_data_with_region (ops_draw (builder, NULL),
-                                      &GRAPHENE_RECT_INIT (
-                                        min_x + (slices[NINE_SLICE_TOP_LEFT].width / scale_x),
-                                        min_y,
-                                        width,
-                                        slices[NINE_SLICE_TOP_CENTER].height / scale_y
-                                      ),
-                                      builder,
-                                      &tregs[NINE_SLICE_TOP_CENTER], TRUE);
-      }
-    /* Top right */
-    if (slice_is_visible (&slices[NINE_SLICE_TOP_RIGHT]))
-      {
-        load_vertex_data_with_region (ops_draw (builder, NULL),
-                                      &GRAPHENE_RECT_INIT (
-                                        max_x - (slices[NINE_SLICE_TOP_RIGHT].width / scale_x),
-                                        min_y,
-                                        slices[NINE_SLICE_TOP_RIGHT].width / scale_x,
-                                        slices[NINE_SLICE_TOP_RIGHT].height / scale_y
-                                      ),
-                                      builder,
-                                      &tregs[NINE_SLICE_TOP_RIGHT], TRUE);
-      }
-
-    /* Bottom right */
-    if (slice_is_visible (&slices[NINE_SLICE_BOTTOM_RIGHT]))
-      {
-        load_vertex_data_with_region (ops_draw (builder, NULL),
-                                      &GRAPHENE_RECT_INIT (
-                                        max_x - (slices[NINE_SLICE_BOTTOM_RIGHT].width / scale_x),
-                                        max_y - (slices[NINE_SLICE_BOTTOM_RIGHT].height / scale_y),
-                                        slices[NINE_SLICE_BOTTOM_RIGHT].width / scale_x,
-                                        slices[NINE_SLICE_BOTTOM_RIGHT].height / scale_y
-                                      ),
-                                      builder,
-                                      &tregs[NINE_SLICE_BOTTOM_RIGHT], TRUE);
-      }
-
-    /* Bottom left */
-    if (slice_is_visible (&slices[NINE_SLICE_BOTTOM_LEFT]))
-      {
-        load_vertex_data_with_region (ops_draw (builder, NULL),
-                                      &GRAPHENE_RECT_INIT (
-                                        min_x,
-                                        max_y - (slices[NINE_SLICE_BOTTOM_LEFT].height / scale_y),
-                                        slices[NINE_SLICE_BOTTOM_LEFT].width / scale_x,
-                                        slices[NINE_SLICE_BOTTOM_LEFT].height / scale_y
-                                      ),
-                                      builder,
-                                      &tregs[NINE_SLICE_BOTTOM_LEFT], TRUE);
-      }
-
-    /* Left side */
-    if (slice_is_visible (&slices[NINE_SLICE_LEFT_CENTER]))
-      {
-        const float height = (max_y - min_y) - (slices[NINE_SLICE_TOP_LEFT].height / scale_y +
-                                                slices[NINE_SLICE_BOTTOM_LEFT].height / scale_y);
-        load_vertex_data_with_region (ops_draw (builder, NULL),
-                                      &GRAPHENE_RECT_INIT (
-                                        min_x,
-                                        min_y + (slices[NINE_SLICE_TOP_LEFT].height / scale_y),
-                                        slices[NINE_SLICE_LEFT_CENTER].width / scale_x,
-                                        height
-                                      ),
-                                      builder,
-                                      &tregs[NINE_SLICE_LEFT_CENTER], TRUE);
-      }
-
-    /* Right side */
-    if (slice_is_visible (&slices[NINE_SLICE_RIGHT_CENTER]))
-      {
-        const float height = (max_y - min_y) - (slices[NINE_SLICE_TOP_RIGHT].height / scale_y +
-                                                slices[NINE_SLICE_BOTTOM_RIGHT].height / scale_y);
-        load_vertex_data_with_region (ops_draw (builder, NULL),
-                                      &GRAPHENE_RECT_INIT (
-                                        max_x - (slices[NINE_SLICE_RIGHT_CENTER].width / scale_x),
-                                        min_y + (slices[NINE_SLICE_TOP_LEFT].height / scale_y),
-                                        slices[NINE_SLICE_RIGHT_CENTER].width / scale_x,
-                                        height
-                                      ),
-                                      builder,
-                                      &tregs[NINE_SLICE_RIGHT_CENTER], TRUE);
-      }
-
-    /* Bottom side */
-    if (slice_is_visible (&slices[NINE_SLICE_BOTTOM_CENTER]))
-      {
-        const float width = (max_x - min_x) - (slices[NINE_SLICE_BOTTOM_LEFT].width / scale_x +
-                                               slices[NINE_SLICE_BOTTOM_RIGHT].width / scale_x);
-        load_vertex_data_with_region (ops_draw (builder, NULL),
-                                      &GRAPHENE_RECT_INIT (
-                                        min_x + (slices[NINE_SLICE_BOTTOM_LEFT].width / scale_x),
-                                        max_y - (slices[NINE_SLICE_BOTTOM_CENTER].height / scale_y),
-                                        width,
-                                        slices[NINE_SLICE_BOTTOM_CENTER].height / scale_y
-                                      ),
-                                      builder,
-                                      &tregs[NINE_SLICE_BOTTOM_CENTER], TRUE);
-      }
-
-    /* Middle */
-    if (slice_is_visible (&slices[NINE_SLICE_CENTER]))
-      {
-        const float width = (max_x - min_x) - (slices[NINE_SLICE_LEFT_CENTER].width / scale_x +
-                                               slices[NINE_SLICE_RIGHT_CENTER].width / scale_x);
-        const float height = (max_y - min_y) - (slices[NINE_SLICE_TOP_CENTER].height / scale_y +
-                                                slices[NINE_SLICE_BOTTOM_CENTER].height / scale_y);
-
-        load_vertex_data_with_region (ops_draw (builder, NULL),
-                                      &GRAPHENE_RECT_INIT (
-                                        min_x + (slices[NINE_SLICE_LEFT_CENTER].width / scale_x),
-                                        min_y + (slices[NINE_SLICE_TOP_CENTER].height / scale_y),
-                                        width, height
-                                      ),
-                                      builder,
-                                      &tregs[NINE_SLICE_CENTER], TRUE);
-      }
-  }
-}
-
-static inline void
-render_shadow_node (GskGLRenderer   *self,
-                    GskRenderNode   *node,
-                    RenderOpBuilder *builder)
-{
-  const gsize n_shadows = gsk_shadow_node_get_n_shadows (node);
-  GskRenderNode *original_child = gsk_shadow_node_get_child (node);
-  GskRenderNode *shadow_child = original_child;
-  guint i;
-
-  /* Shadow nodes recolor every pixel of the source texture, but leave the alpha in tact.
-   * If the child is a color matrix node that doesn't touch the alpha, we can throw that away. */
-  if (gsk_render_node_get_node_type (shadow_child) == GSK_COLOR_MATRIX_NODE &&
-      !color_matrix_modifies_alpha (shadow_child))
-    {
-      shadow_child = gsk_color_matrix_node_get_child (shadow_child);
-    }
-
-  for (i = 0; i < n_shadows; i ++)
-    {
-      const GskShadow *shadow = gsk_shadow_node_get_shadow (node, i);
-      const float dx = shadow->dx;
-      const float dy = shadow->dy;
-      TextureRegion region;
-      gboolean is_offscreen;
-      graphene_rect_t bounds;
-
-      if (shadow->radius == 0 &&
-          gsk_render_node_get_node_type (shadow_child) == GSK_TEXT_NODE)
-        {
-          ops_offset (builder, dx, dy);
-          render_text_node (self, shadow_child, builder, &shadow->color, TRUE);
-          ops_offset (builder, - dx, - dy);
-          continue;
-        }
-
-      if (gdk_rgba_is_clear (&shadow->color))
-        continue;
-
-      if (node_is_invisible (shadow_child))
-        continue;
-
-      if (shadow->radius > 0)
-        {
-          float min_x;
-          float min_y;
-          float max_x;
-          float max_y;
-
-          region.texture_id = 0;
-          blur_node (self, shadow_child, builder, shadow->radius, NO_CACHE_PLZ, &region,
-                     (float*[4]){&min_x, &max_x, &min_y, &max_y});
-          bounds.origin.x = min_x - builder->dx;
-          bounds.origin.y = min_y - builder->dy;
-          bounds.size.width = max_x - min_x;
-          bounds.size.height = max_y - min_y;
-          is_offscreen = TRUE;
-        }
-      else if (dx == 0 && dy == 0)
-        {
-          continue; /* Invisible anyway */
-        }
-      else
-        {
-          if (!add_offscreen_ops (self, builder,
-                                  &shadow_child->bounds,
-                                  shadow_child, &region, &is_offscreen,
-                                  RESET_CLIP | NO_CACHE_PLZ))
-            g_assert_not_reached ();
-
-          bounds = shadow_child->bounds;
-        }
-
-      ops_set_program (builder, &self->programs->coloring_program);
-      ops_set_color (builder, &shadow->color);
-      ops_set_texture (builder, region.texture_id);
-
-      ops_offset (builder, dx, dy);
-      load_vertex_data_with_region (ops_draw (builder, NULL),
-                                    &bounds, builder,
-                                    &region,
-                                    is_offscreen);
-      ops_offset (builder, -dx, -dy);
-    }
-
-  /* Now draw the child normally */
-  gsk_gl_renderer_add_render_ops (self, original_child, builder);
-}
-
-static inline void
-render_cross_fade_node (GskGLRenderer   *self,
-                        GskRenderNode   *node,
-                        RenderOpBuilder *builder)
-{
-  GskRenderNode *start_node = gsk_cross_fade_node_get_start_child (node);
-  GskRenderNode *end_node = gsk_cross_fade_node_get_end_child (node);
-  const float progress = gsk_cross_fade_node_get_progress (node);
-  TextureRegion start_region;
-  TextureRegion end_region;
-  gboolean is_offscreen1, is_offscreen2;
-  OpCrossFade *op;
-
-  if (progress <= 0)
-    {
-      gsk_gl_renderer_add_render_ops (self, start_node, builder);
-      return;
-    }
-  else if (progress >= 1)
-    {
-      gsk_gl_renderer_add_render_ops (self, end_node, builder);
-      return;
-    }
-
-  if (equal_texture_nodes (start_node, end_node))
-    {
-      gsk_gl_renderer_add_render_ops (self, end_node, builder);
-      return;
-    }
-
-  /* TODO: We create 2 textures here as big as the cross-fade node, but both the
-   * start and the end node might be a lot smaller than that. */
-
-  if (!add_offscreen_ops (self, builder,
-                          &node->bounds,
-                          start_node,
-                          &start_region, &is_offscreen1,
-                          FORCE_OFFSCREEN | RESET_CLIP))
-    {
-      gsk_gl_renderer_add_render_ops (self, end_node, builder);
-      return;
-    }
-
-  if (!add_offscreen_ops (self, builder,
-                          &node->bounds,
-                          end_node,
-                          &end_region, &is_offscreen2,
-                          FORCE_OFFSCREEN | RESET_CLIP))
-    {
-      const float prev_opacity = ops_set_opacity (builder, builder->current_opacity * progress);
-      gsk_gl_renderer_add_render_ops (self, start_node, builder);
-      ops_set_opacity (builder, prev_opacity);
-
-      return;
-    }
-
-  ops_set_program (builder, &self->programs->cross_fade_program);
-
-  op = ops_begin (builder, OP_CHANGE_CROSS_FADE);
-  op->progress = progress;
-  op->source2 = end_region.texture_id;
-
-  ops_set_texture (builder, start_region.texture_id);
-
-  load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
-}
-
-static inline void
-render_blend_node (GskGLRenderer   *self,
-                   GskRenderNode   *node,
-                   RenderOpBuilder *builder)
-{
-  GskRenderNode *top_child = gsk_blend_node_get_top_child (node);
-  GskRenderNode *bottom_child = gsk_blend_node_get_bottom_child (node);
-  TextureRegion top_region;
-  TextureRegion bottom_region;
-  gboolean is_offscreen1, is_offscreen2;
-  OpBlend *op;
-
-  /* TODO: We create 2 textures here as big as the blend node, but both the
-   * start and the end node might be a lot smaller than that. */
-  if (!add_offscreen_ops (self, builder,
-                          &node->bounds,
-                          bottom_child,
-                          &bottom_region, &is_offscreen1,
-                          FORCE_OFFSCREEN | RESET_CLIP))
-    {
-      gsk_gl_renderer_add_render_ops (self, top_child, builder);
-      return;
-    }
-
-  if (!add_offscreen_ops (self, builder,
-                          &node->bounds,
-                          top_child,
-                          &top_region, &is_offscreen2,
-                          FORCE_OFFSCREEN | RESET_CLIP))
-    {
-      load_vertex_data_with_region (ops_draw (builder, NULL),
-                                    &node->bounds,
-                                    builder,
-                                    &bottom_region,
-                                    TRUE);
-      return;
-    }
-
-  ops_set_program (builder, &self->programs->blend_program);
-  ops_set_texture (builder, bottom_region.texture_id);
-
-  op = ops_begin (builder, OP_CHANGE_BLEND);
-  op->source2 = top_region.texture_id;
-  op->mode = gsk_blend_node_get_blend_mode (node);
-
-  load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
-}
-
-static inline void
-render_repeat_node (GskGLRenderer   *self,
-                    GskRenderNode   *node,
-                    RenderOpBuilder *builder)
-{
-  GskRenderNode *child = gsk_repeat_node_get_child (node);
-  const graphene_rect_t *child_bounds = gsk_repeat_node_get_child_bounds (node);
-  TextureRegion region;
-  gboolean is_offscreen;
-  OpRepeat *op;
-
-  if (node_is_invisible (child))
-    return;
-
-  if (!graphene_rect_equal (child_bounds, &child->bounds))
-    {
-      /* TODO: Implement these repeat nodes. */
-      render_fallback_node (self, node, builder);
-      return;
-    }
-
-  /* If the size of the repeat node is smaller than the size of the
-   * child node, we don't repeat at all and can just draw that part
-   * of the child texture... */
-  if (graphene_rect_contains_rect (child_bounds, &node->bounds))
-    {
-      render_clipped_child (self, builder, &node->bounds, child);
-      return;
-    }
-
-  /* Draw the entire child on a texture */
-  if (!add_offscreen_ops (self, builder,
-                          &child->bounds,
-                          child,
-                          &region, &is_offscreen,
-                          RESET_CLIP))
-    g_assert_not_reached ();
-
-  ops_set_program (builder, &self->programs->repeat_program);
-  ops_set_texture (builder, region.texture_id);
-
-  op = ops_begin (builder, OP_CHANGE_REPEAT);
-  op->child_bounds[0] = (node->bounds.origin.x - child_bounds->origin.x) / child_bounds->size.width;
-  op->child_bounds[1] = (node->bounds.origin.y - child_bounds->origin.y) / child_bounds->size.height;
-  op->child_bounds[2] = node->bounds.size.width / child_bounds->size.width;
-  op->child_bounds[3] = node->bounds.size.height / child_bounds->size.height;
-
-  op->texture_rect[0] = region.x;
-  op->texture_rect[2] = region.x2;
-
-  if (is_offscreen)
-    {
-      op->texture_rect[1] = region.y2;
-      op->texture_rect[3] = region.y;
-    }
-  else
-    {
-      op->texture_rect[1] = region.y;
-      op->texture_rect[3] = region.y2;
-    }
-
-  load_vertex_data_with_region (ops_draw (builder, NULL),
-                                &node->bounds, builder,
-                                &region,
-                                is_offscreen);
-}
-
-static inline void
-apply_viewport_op (const Program    *program,
-                   const OpViewport *op)
-{
-  OP_PRINT (" -> New Viewport: %f, %f, %f, %f",
-            op->viewport.origin.x, op->viewport.origin.y,
-            op->viewport.size.width, op->viewport.size.height);
-  glUniform4f (program->viewport_location,
-               op->viewport.origin.x, op->viewport.origin.y,
-               op->viewport.size.width, op->viewport.size.height);
-  glViewport (0, 0, op->viewport.size.width, op->viewport.size.height);
-}
-
-static inline void
-apply_modelview_op (const Program  *program,
-                    const OpMatrix *op)
-{
-  float mat[16];
-
-  graphene_matrix_to_float (&op->matrix, mat);
-  OP_PRINT (" -> Modelview { { %f,%f,%f,%f }, { %f,%f,%f,%f }, { %f,%f,%f,%f }, { %f,%f,%f,%f }",
-            mat[0], mat[1], mat[2], mat[3],
-            mat[4], mat[5], mat[6], mat[7],
-            mat[8], mat[9], mat[10], mat[11],
-            mat[12], mat[13], mat[14], mat[15]);
-  glUniformMatrix4fv (program->modelview_location, 1, GL_FALSE, mat);
-}
-
-static inline void
-apply_projection_op (const Program  *program,
-                     const OpMatrix *op)
-{
-  float mat[16];
-
-  graphene_matrix_to_float (&op->matrix, mat);
-  OP_PRINT (" -> Projection { { %f,%f,%f,%f }, { %f,%f,%f,%f }, { %f,%f,%f,%f }, { %f,%f,%f,%f }",
-            mat[0], mat[1], mat[2], mat[3],
-            mat[4], mat[5], mat[6], mat[7],
-            mat[8], mat[9], mat[10], mat[11],
-            mat[12], mat[13], mat[14], mat[15]);
-  glUniformMatrix4fv (program->projection_location, 1, GL_FALSE, mat);
-}
-
-static inline void
-apply_program_op (const Program  *program,
-                  const OpProgram *op)
-{
-  OP_PRINT (" -> Program: %d", op->program->index);
-  glUseProgram (op->program->id);
-}
-
-static inline void
-apply_render_target_op (GskGLRenderer        *self,
-                        const OpRenderTarget *op)
-{
-  OP_PRINT (" -> Render Target: %d", op->render_target_id);
-
-  glBindFramebuffer (GL_FRAMEBUFFER, op->render_target_id);
-
-  if (op->render_target_id != 0)
-    glDisable (GL_SCISSOR_TEST);
-  else
-    gsk_gl_renderer_setup_render_mode (self); /* Reset glScissor etc. */
-}
-
-static inline void
-apply_color_op (const Program *program,
-                const OpColor *op)
-{
-  OP_PRINT (" -> Color: (%f, %f, %f, %f)",
-            op->rgba->red, op->rgba->green, op->rgba->blue, op->rgba->alpha);
-  glUniform4fv (program->color.color_location, 1, (float *)op->rgba);
-}
-
-static inline void
-apply_opacity_op (const Program   *program,
-                  const OpOpacity *op)
-{
-  OP_PRINT (" -> Opacity %f", op->opacity);
-  glUniform1f (program->alpha_location, op->opacity);
-}
-
-static inline void
-apply_source_texture_op (const Program   *program,
-                         const OpTexture *op)
-{
-  g_assert(op->texture_id != 0);
-  OP_PRINT (" -> New texture: %d", op->texture_id);
-  /* Use texture unit 0 for the source */
-  glUniform1i (program->source_location, 0);
-  glActiveTexture (GL_TEXTURE0);
-  glBindTexture (GL_TEXTURE_2D, op->texture_id);
-}
-
-static inline void
-apply_source_extra_texture_op (const Program        *program,
-                               const OpExtraTexture *op)
-{
-  g_assert(op->texture_id != 0);
-  OP_PRINT (" -> New extra texture %d: %d", op->idx, op->texture_id);
-  glUniform1i (program->glshader.texture_locations[op->idx], op->idx);
-  glActiveTexture (GL_TEXTURE0 + op->idx);
-  glBindTexture (GL_TEXTURE_2D, op->texture_id);
-}
-
-static inline void
-apply_color_matrix_op (const Program       *program,
-                       const OpColorMatrix *op)
-{
-  OP_PRINT (" -> Color matrix. Send matrix: %d. Send offset: %d.",
-            op->matrix.send, op->offset.send);
-
-  if (op->matrix.send)
-    {
-      float mat[16];
-      graphene_matrix_to_float (op->matrix.value, mat);
-      glUniformMatrix4fv (program->color_matrix.color_matrix_location, 1, GL_FALSE, mat);
-    }
-
-  if (op->offset.send)
-    {
-      float vec[4];
-      graphene_vec4_to_float (op->offset.value, vec);
-      glUniform4fv (program->color_matrix.color_offset_location, 1, vec);
-    }
-}
-
-static inline void
-apply_clip_op (const Program *program,
-               const OpClip  *op)
-{
-  int count;
-
-  if (op->send_corners)
-    {
-      OP_PRINT (" -> Clip: %s", gsk_rounded_rect_to_string (&op->clip));
-      count = 3;
-    }
-  else
-    {
-      OP_PRINT (" -> clip: %f, %f, %f, %f",
-                op->clip.bounds.origin.x, op->clip.bounds.origin.y,
-                op->clip.bounds.size.width, op->clip.bounds.size.height);
-      count = 1;
-    }
-
-  glUniform4fv (program->clip_rect_location, count, (float *)&op->clip.bounds);
-}
-
-static inline void
-apply_inset_shadow_op (const Program  *program,
-                       const OpShadow *op)
-{
-  OP_PRINT (" -> inset shadow. Color: %s, Offset: (%f, %f), Spread: %f, Outline: %s",
-            op->color.send ? gdk_rgba_to_string (op->color.value) : "don't send",
-            op->offset.send ? op->offset.value[0] : -1337.0,
-            op->offset.send ? op->offset.value[1] : -1337.0,
-            op->spread.send ? op->spread.value : -1337.0,
-            op->outline.send ? gsk_rounded_rect_to_string (&op->outline.value) : "don't send");
-  if (op->outline.send)
-    {
-      if (op->outline.send_corners)
-        glUniform4fv (program->inset_shadow.outline_rect_location, 3, (float *)&op->outline.value);
-      else
-        glUniform4fv (program->inset_shadow.outline_rect_location, 1, (float *)&op->outline.value);
-    }
-
-  if (op->color.send)
-    glUniform4fv (program->inset_shadow.color_location, 1, (float *)op->color.value);
-
-  if (op->spread.send)
-    glUniform1f (program->inset_shadow.spread_location, op->spread.value);
-
-  if (op->offset.send)
-    glUniform2fv (program->inset_shadow.offset_location, 1, op->offset.value);
-}
-
-static inline void
-apply_unblurred_outset_shadow_op (const Program  *program,
-                                  const OpShadow *op)
-{
-  OP_PRINT (" -> unblurred outset shadow");
-
-  if (op->outline.send)
-    {
-      if (op->outline.send_corners)
-        glUniform4fv (program->unblurred_outset_shadow.outline_rect_location, 3, (float *)&op->outline.value);
-      else
-        glUniform4fv (program->unblurred_outset_shadow.outline_rect_location, 1, (float *)&op->outline.value);
-    }
-
-  if (op->color.send)
-    glUniform4fv (program->unblurred_outset_shadow.color_location, 1, (float *)op->color.value);
-
-  if (op->spread.send)
-    glUniform1f (program->unblurred_outset_shadow.spread_location, op->spread.value);
-
-  if (op->offset.send)
-    glUniform2fv (program->unblurred_outset_shadow.offset_location, 1, op->offset.value);
-}
-
-static inline void
-apply_outset_shadow_op (const Program        *program,
-                        const OpOutsetShadow *op)
-{
-  OP_PRINT (" -> outset shadow");
-  glUniform4fv (program->outset_shadow.outline_rect_location, 3, (float *)&op->outline.value.bounds);
-}
-
-static inline void
-apply_linear_gradient_op (const Program          *program,
-                          const OpLinearGradient *op)
-{
-  OP_PRINT (" -> Linear gradient");
-  if (op->n_color_stops.send)
-    glUniform1i (program->linear_gradient.num_color_stops_location, op->n_color_stops.value);
-
-  if (op->color_stops.send)
-    glUniform1fv (program->linear_gradient.color_stops_location,
-                  op->n_color_stops.value * 5,
-                  (float *)op->color_stops.value);
-
-  glUniform4f (program->linear_gradient.points_location,
-               op->start_point[0], op->start_point[1],
-               op->end_point[0] - op->start_point[0], op->end_point[1] - op->start_point[1]);
-  glUniform1i (program->linear_gradient.repeat_location, op->repeat);
-}
-
-static inline void
-apply_radial_gradient_op (const Program          *program,
-                          const OpRadialGradient *op)
-{
-  float scale;
-  float bias;
-
-  OP_PRINT (" -> Radial gradient");
-  if (op->n_color_stops.send)
-    glUniform1i (program->radial_gradient.num_color_stops_location, op->n_color_stops.value);
-
-  if (op->color_stops.send)
-    glUniform1fv (program->radial_gradient.color_stops_location,
-                  op->n_color_stops.value * 5,
-                  (float *)op->color_stops.value);
-
-  scale = 1.0f / (op->end - op->start);
-  bias = -op->start * scale;
-
-  glUniform1i (program->radial_gradient.repeat_location, op->repeat);
-  glUniform2f (program->radial_gradient.range_location, scale, bias);
-  glUniform4f (program->radial_gradient.geometry_location,
-               op->center[0], op->center[1],
-               1.0f / op->radius[0], 1.0f / op->radius[1]);
-}
-
-static inline void
-apply_conic_gradient_op (const Program         *program,
-                         const OpConicGradient *op)
-{
-  float bias;
-  float scale;
-
-  OP_PRINT (" -> Conic gradient");
-  if (op->n_color_stops.send)
-    glUniform1i (program->conic_gradient.num_color_stops_location, op->n_color_stops.value);
-
-  if (op->color_stops.send)
-    glUniform1fv (program->conic_gradient.color_stops_location,
-                  op->n_color_stops.value * 5,
-                  (float *)op->color_stops.value);
-
-  scale = 0.5f * M_1_PI;
-  bias = op->angle * scale + 2.0f;
-  glUniform4f (program->conic_gradient.geometry_location, op->center[0], op->center[1], scale, bias);
-}
-
-static inline void
-apply_border_op (const Program  *program,
-                 const OpBorder *op)
-{
-  OP_PRINT (" -> Border Outline");
-
-  glUniform4fv (program->border.outline_rect_location, 3, (float *)&op->outline.bounds);
-}
-
-static inline void
-apply_gl_shader_args_op (const Program  *program,
-                         const OpGLShader *op)
-{
-  int n_uniforms, i;
-  const GskGLUniform *uniforms;
-
-  OP_PRINT (" -> GL Shader Args");
-
-  glUniform2fv (program->glshader.size_location, 1, op->size);
-
-  uniforms = gsk_gl_shader_get_uniforms (op->shader, &n_uniforms);
-  for (i = 0; i < n_uniforms; i++)
-    {
-      const GskGLUniform *u = &uniforms[i];
-      const guchar *data = op->uniform_data + u->offset;
-
-      switch (u->type)
-        {
-        default:
-        case GSK_GL_UNIFORM_TYPE_NONE:
-          break;
-        case GSK_GL_UNIFORM_TYPE_FLOAT:
-          glUniform1fv (program->glshader.args_locations[i], 1, (const float *)data);
-          break;
-        case GSK_GL_UNIFORM_TYPE_INT:
-          glUniform1iv (program->glshader.args_locations[i], 1, (const gint32 *)data);
-          break;
-        case GSK_GL_UNIFORM_TYPE_UINT:
-        case GSK_GL_UNIFORM_TYPE_BOOL:
-          glUniform1uiv (program->glshader.args_locations[i], 1, (const guint32 *) data);
-          break;
-        case GSK_GL_UNIFORM_TYPE_VEC2:
-          glUniform2fv (program->glshader.args_locations[i], 1, (const float *)data);
-          break;
-        case GSK_GL_UNIFORM_TYPE_VEC3:
-          glUniform3fv (program->glshader.args_locations[i], 1, (const float *)data);
-          break;
-        case GSK_GL_UNIFORM_TYPE_VEC4:
-          glUniform4fv (program->glshader.args_locations[i], 1, (const float *)data);
-          break;
-        }
-    }
-}
-
-static inline void
-apply_border_width_op (const Program  *program,
-                       const OpBorder *op)
-{
-  OP_PRINT (" -> Border width (%f, %f, %f, %f)",
-            op->widths[0], op->widths[1], op->widths[2], op->widths[3]);
-
-  glUniform4fv (program->border.widths_location, 1, op->widths);
-}
-
-static inline void
-apply_border_color_op (const Program  *program,
-                       const OpBorder *op)
-{
-  OP_PRINT (" -> Border color: %s", gdk_rgba_to_string (op->color));
-  glUniform4fv (program->border.color_location, 1, (float *)op->color);
-}
-
-static inline void
-apply_blur_op (const Program *program,
-               const OpBlur  *op)
-{
-  OP_PRINT (" -> Blur");
-  glUniform1f (program->blur.blur_radius_location, op->radius);
-  glUniform2f (program->blur.blur_size_location, op->size.width, op->size.height);
-  glUniform2f (program->blur.blur_dir_location, op->dir[0], op->dir[1]);
-}
-
-static inline void
-apply_cross_fade_op (const Program     *program,
-                     const OpCrossFade *op)
-{
-  OP_PRINT (" -> Cross fade");
-  /* End texture id */
-  glUniform1i (program->cross_fade.source2_location, 1);
-  glActiveTexture (GL_TEXTURE0 + 1);
-  glBindTexture (GL_TEXTURE_2D, op->source2);
-  /* progress */
-  glUniform1f (program->cross_fade.progress_location, op->progress);
-}
-
-static inline void
-apply_blend_op (const Program *program,
-                const OpBlend *op)
-{
-  /* End texture id */
-  glUniform1i (program->blend.source2_location, 1);
-  glActiveTexture (GL_TEXTURE0 + 1);
-  glBindTexture (GL_TEXTURE_2D, op->source2);
-  /* progress */
-  glUniform1i (program->blend.mode_location, op->mode);
-}
-
-static inline void
-apply_repeat_op (const Program  *program,
-                 const OpRepeat *op)
-{
-  OP_PRINT (" -> Repeat");
-  glUniform4fv (program->repeat.child_bounds_location, 1, op->child_bounds);
-  glUniform4fv (program->repeat.texture_rect_location, 1, op->texture_rect);
-}
-
-static void
-gsk_gl_renderer_dispose (GObject *gobject)
-{
-  GskGLRenderer *self = GSK_GL_RENDERER (gobject);
-
-  ops_free (&self->op_builder);
-
-  G_OBJECT_CLASS (gsk_gl_renderer_parent_class)->dispose (gobject);
-}
-
-static void
-program_init (Program *program)
-{
-  program->index = -1;
-  program->state.opacity = 1.0f;
-}
-
-static void
-program_finalize (Program *program)
-{
-  if (program->id > 0)
-    glDeleteProgram (program->id);
-  if (program->index == -1 &&
-      program->glshader.compile_error != NULL)
-    g_error_free (program->glshader.compile_error);
-
-  gsk_transform_unref (program->state.modelview);
-}
-
-static void
-program_free (Program *program)
-{
-  program_finalize (program);
-  g_free (program);
-}
-
-static GskGLRendererPrograms *
-gsk_gl_renderer_programs_new (void)
-{
-  GskGLRendererPrograms *programs;
-  int i;
-
-  programs = g_new0 (GskGLRendererPrograms, 1);
-  programs->ref_count = 1;
-  for (i = 0; i < GL_N_PROGRAMS; i ++)
-    program_init (&programs->programs[i]);
-
-  /* We use direct hash for performance, not string hash on the source, because we assume each caller
-   * reuses a single GskGLShader for all uses and different callers will use different source content. */
-  programs->custom_programs = g_hash_table_new_full (g_direct_hash, g_direct_equal, (GDestroyNotify)g_object_unref, (GDestroyNotify)program_free);
-
-  return programs;
-}
-
-static GskGLRendererPrograms *
-gsk_gl_renderer_programs_ref (GskGLRendererPrograms *programs)
-{
-  programs->ref_count++;
-  return programs;
-}
-
-/* Must be called with the context current */
-static void
-gsk_gl_renderer_programs_unref (GskGLRendererPrograms *programs)
-{
-  int i;
-  programs->ref_count--;
-  if (programs->ref_count == 0)
-    {
-      for (i = 0; i < GL_N_PROGRAMS; i ++)
-        program_finalize (&programs->programs[i]);
-
-      g_hash_table_destroy (programs->custom_programs);
-      g_free (programs);
-    }
-}
-
-static Program *
-gsk_gl_renderer_lookup_custom_program (GskGLRenderer  *self,
-                                       GskGLShader *shader)
-{
-  return g_hash_table_lookup (self->programs->custom_programs, shader);
-}
-
-static Program *
-gsk_gl_renderer_create_custom_program (GskGLRenderer  *self,
-                                       GskGLShader *shader)
-{
-  Program *program = g_new0 (Program, 1);
-
-  program_init (program);
-
-  g_hash_table_insert (self->programs->custom_programs, g_object_ref (shader), program);
-
-  return program;
-}
-
-static GskGLRendererPrograms *
-gsk_gl_renderer_create_programs (GskGLRenderer  *self,
-                                 GError        **error)
-{
-  GskGLShaderBuilder shader_builder;
-  GskGLRendererPrograms *programs = NULL;
-  int i;
-  static const struct {
-    const char *resource_path;
-    const char *name;
-  } program_definitions[] = {
-    { "/org/gtk/libgsk/gl/blend.glsl",                     "blend" },
-    { "/org/gtk/libgsk/gl/blit.glsl",                      "blit" },
-    { "/org/gtk/libgsk/gl/blur.glsl",                      "blur" },
-    { "/org/gtk/libgsk/gl/border.glsl",                    "border" },
-    { "/org/gtk/libgsk/gl/color_matrix.glsl",              "color matrix" },
-    { "/org/gtk/libgsk/gl/color.glsl",                     "color" },
-    { "/org/gtk/libgsk/gl/coloring.glsl",                  "coloring" },
-    { "/org/gtk/libgsk/gl/cross_fade.glsl",                "cross fade" },
-    { "/org/gtk/libgsk/gl/inset_shadow.glsl",              "inset shadow" },
-    { "/org/gtk/libgsk/gl/linear_gradient.glsl",           "linear gradient" },
-    { "/org/gtk/libgsk/gl/radial_gradient.glsl",           "radial gradient" },
-    { "/org/gtk/libgsk/gl/conic_gradient.glsl",            "conic gradient" },
-    { "/org/gtk/libgsk/gl/outset_shadow.glsl",             "outset shadow" },
-    { "/org/gtk/libgsk/gl/repeat.glsl",                    "repeat" },
-    { "/org/gtk/libgsk/gl/unblurred_outset_shadow.glsl",   "unblurred_outset shadow" },
-  };
-
-  gsk_gl_shader_builder_init (&shader_builder,
-                              "/org/gtk/libgsk/gl/preamble.glsl",
-                              "/org/gtk/libgsk/gl/preamble.vs.glsl",
-                              "/org/gtk/libgsk/gl/preamble.fs.glsl");
-
-  g_assert (G_N_ELEMENTS (program_definitions) == GL_N_PROGRAMS);
-
-  init_shader_builder (self, &shader_builder);
-
-  programs = gsk_gl_renderer_programs_new ();
-
-  for (i = 0; i < GL_N_PROGRAMS; i ++)
-    {
-      Program *prog = &programs->programs[i];
-
-      prog->name = program_definitions[i].name;
-      prog->index = i;
-      prog->id = gsk_gl_shader_builder_create_program (&shader_builder,
-                                                       program_definitions[i].resource_path,
-                                                       NULL, 0, error);
-      if (prog->id < 0)
-        {
-          g_clear_pointer (&programs, gsk_gl_renderer_programs_unref);
-          goto out;
-        }
-
-      INIT_COMMON_UNIFORM_LOCATION (prog, alpha);
-      INIT_COMMON_UNIFORM_LOCATION (prog, source);
-      INIT_COMMON_UNIFORM_LOCATION (prog, clip_rect);
-      INIT_COMMON_UNIFORM_LOCATION (prog, viewport);
-      INIT_COMMON_UNIFORM_LOCATION (prog, projection);
-      INIT_COMMON_UNIFORM_LOCATION (prog, modelview);
-    }
-  /* color */
-  INIT_PROGRAM_UNIFORM_LOCATION (color, color);
-
-  /* coloring */
-  INIT_PROGRAM_UNIFORM_LOCATION (coloring, color);
-
-  /* color matrix */
-  INIT_PROGRAM_UNIFORM_LOCATION (color_matrix, color_matrix);
-  INIT_PROGRAM_UNIFORM_LOCATION (color_matrix, color_offset);
-
-  /* linear gradient */
-  INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient, color_stops);
-  INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient, num_color_stops);
-  INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient, repeat);
-  INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient, points);
-
-  /* radial gradient */
-  INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, color_stops);
-  INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, num_color_stops);
-  INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, repeat);
-  INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, geometry);
-  INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, range);
-
-  /* conic gradient */
-  INIT_PROGRAM_UNIFORM_LOCATION (conic_gradient, color_stops);
-  INIT_PROGRAM_UNIFORM_LOCATION (conic_gradient, num_color_stops);
-  INIT_PROGRAM_UNIFORM_LOCATION (conic_gradient, geometry);
-
-  /* blur */
-  INIT_PROGRAM_UNIFORM_LOCATION (blur, blur_radius);
-  INIT_PROGRAM_UNIFORM_LOCATION (blur, blur_size);
-  INIT_PROGRAM_UNIFORM_LOCATION (blur, blur_dir);
-
-  /* inset shadow */
-  INIT_PROGRAM_UNIFORM_LOCATION (inset_shadow, color);
-  INIT_PROGRAM_UNIFORM_LOCATION (inset_shadow, spread);
-  INIT_PROGRAM_UNIFORM_LOCATION (inset_shadow, offset);
-  INIT_PROGRAM_UNIFORM_LOCATION (inset_shadow, outline_rect);
-
-  /* outset shadow */
-  INIT_PROGRAM_UNIFORM_LOCATION (outset_shadow, color);
-  INIT_PROGRAM_UNIFORM_LOCATION (outset_shadow, outline_rect);
-
-  /* unblurred outset shadow */
-  INIT_PROGRAM_UNIFORM_LOCATION (unblurred_outset_shadow, color);
-  INIT_PROGRAM_UNIFORM_LOCATION (unblurred_outset_shadow, spread);
-  INIT_PROGRAM_UNIFORM_LOCATION (unblurred_outset_shadow, offset);
-  INIT_PROGRAM_UNIFORM_LOCATION (unblurred_outset_shadow, outline_rect);
-
-  /* border */
-  INIT_PROGRAM_UNIFORM_LOCATION (border, color);
-  INIT_PROGRAM_UNIFORM_LOCATION (border, widths);
-  INIT_PROGRAM_UNIFORM_LOCATION (border, outline_rect);
-
-  /* cross fade */
-  INIT_PROGRAM_UNIFORM_LOCATION (cross_fade, progress);
-  INIT_PROGRAM_UNIFORM_LOCATION (cross_fade, source2);
-
-  /* blend */
-  INIT_PROGRAM_UNIFORM_LOCATION (blend, source2);
-  INIT_PROGRAM_UNIFORM_LOCATION (blend, mode);
-
-  /* repeat */
-  INIT_PROGRAM_UNIFORM_LOCATION (repeat, child_bounds);
-  INIT_PROGRAM_UNIFORM_LOCATION (repeat, texture_rect);
-
-
-  /* We initialize the alpha uniform here, since the default value is important.
-   * We can't do it in the shader like a reasonable person would because that doesn't
-   * work in gles. */
-  for (i = 0; i < GL_N_PROGRAMS; i++)
-    {
-      glUseProgram(programs->programs[i].id);
-      glUniform1f (programs->programs[i].alpha_location, 1.0);
-    }
-
-out:
-  gsk_gl_shader_builder_finish (&shader_builder);
-
-  /* Check we indeed emitted an error if there was one */
-  g_assert (programs || !error || *error);
-
-  return programs;
-}
-
-static GskGLRendererPrograms *
-get_programs_for_display (GskGLRenderer  *self,
-                          GdkDisplay     *display,
-                          GError        **error)
-{
-  GskGLRendererPrograms *programs;
-
-  if (g_getenv ("GSK_NO_SHARED_PROGRAMS"))
-    return gsk_gl_renderer_create_programs (self, error);
-
-  programs = (GskGLRendererPrograms *)g_object_get_data (G_OBJECT (display), "gsk-gl-programs");
-  if (programs == NULL)
-    {
-      programs = gsk_gl_renderer_create_programs (self, error);
-      if (programs)
-        g_object_set_data_full (G_OBJECT (display), "gsk-gl-programs",
-                                programs,
-                                (GDestroyNotify) gsk_gl_renderer_programs_unref);
-    }
-
-  if (programs)
-    return gsk_gl_renderer_programs_ref (programs);
-  return NULL;
-}
-
-
-static GskGLTextureAtlases *
-get_texture_atlases_for_display (GdkDisplay *display)
-{
-  GskGLTextureAtlases *atlases;
-
-  if (g_getenv ("GSK_NO_SHARED_CACHES"))
-    return gsk_gl_texture_atlases_new ();
-
-  atlases = (GskGLTextureAtlases*)g_object_get_data (G_OBJECT (display), "gsk-gl-texture-atlases");
-  if (atlases == NULL)
-    {
-      atlases = gsk_gl_texture_atlases_new ();
-      g_object_set_data_full (G_OBJECT (display), "gsk-gl-texture-atlases",
-                              atlases,
-                              (GDestroyNotify) gsk_gl_texture_atlases_unref);
-    }
-
-  return gsk_gl_texture_atlases_ref (atlases);
-}
-
-static GskGLGlyphCache *
-get_glyph_cache_for_display (GdkDisplay *display,
-                             GskGLTextureAtlases *atlases)
-{
-  GskGLGlyphCache *glyph_cache;
-
-  if (g_getenv ("GSK_NO_SHARED_CACHES"))
-    return gsk_gl_glyph_cache_new (display, atlases);
-
-  glyph_cache = (GskGLGlyphCache*)g_object_get_data (G_OBJECT (display), "gsk-gl-glyph-cache");
-  if (glyph_cache == NULL)
-    {
-      glyph_cache = gsk_gl_glyph_cache_new (display, atlases);
-      g_object_set_data_full (G_OBJECT (display), "gsk-gl-glyph-cache",
-                              glyph_cache,
-                              (GDestroyNotify) gsk_gl_glyph_cache_unref);
-    }
-
-  return gsk_gl_glyph_cache_ref (glyph_cache);
-}
-
-static GskGLIconCache *
-get_icon_cache_for_display (GdkDisplay *display,
-                            GskGLTextureAtlases *atlases)
-{
-  GskGLIconCache *icon_cache;
-
-  if (g_getenv ("GSK_NO_SHARED_CACHES"))
-    return gsk_gl_icon_cache_new (display, atlases);
-
-  icon_cache = (GskGLIconCache*)g_object_get_data (G_OBJECT (display), "gsk-gl-icon-cache");
-  if (icon_cache == NULL)
-    {
-      icon_cache = gsk_gl_icon_cache_new (display, atlases);
-      g_object_set_data_full (G_OBJECT (display), "gsk-gl-icon-cache",
-                              icon_cache,
-                              (GDestroyNotify) gsk_gl_icon_cache_unref);
-    }
-
-  return gsk_gl_icon_cache_ref (icon_cache);
-}
-
-static gboolean
-gsk_gl_renderer_realize (GskRenderer  *renderer,
-                         GdkSurface    *surface,
-                         GError      **error)
-{
-  GskGLRenderer *self = GSK_GL_RENDERER (renderer);
-  gint64 before G_GNUC_UNUSED;
-
-  before = GDK_PROFILER_CURRENT_TIME;
-  /* If we didn't get a GdkGLContext before realization, try creating
-   * one now, for our exclusive use.
-   */
-  if (self->gl_context == NULL)
-    {
-      self->gl_context = gdk_surface_create_gl_context (surface, error);
-      if (self->gl_context == NULL)
-        return FALSE;
-    }
-
-  if (!gdk_gl_context_realize (self->gl_context, error))
-    return FALSE;
-
-  gdk_gl_context_make_current (self->gl_context);
-
-  g_assert (self->gl_driver == NULL);
-  self->gl_profiler = gsk_gl_profiler_new (self->gl_context);
-  self->gl_driver = gsk_gl_driver_new (self->gl_context);
-
-  GSK_RENDERER_NOTE (renderer, OPENGL, g_message ("Creating buffers and programs"));
-  self->programs = get_programs_for_display (self, gdk_surface_get_display (surface), error);
-  if (self->programs == NULL)
-    return FALSE;
-  self->op_builder.programs = self->programs;
-
-  self->atlases = get_texture_atlases_for_display (gdk_surface_get_display (surface));
-  self->glyph_cache = get_glyph_cache_for_display (gdk_surface_get_display (surface), self->atlases);
-  self->icon_cache = get_icon_cache_for_display (gdk_surface_get_display (surface), self->atlases);
-  gsk_gl_shadow_cache_init (&self->shadow_cache);
-
-  gdk_profiler_end_mark (before, "gl renderer realize", NULL);
-
-  return TRUE;
-}
-
-static void
-gsk_gl_renderer_unrealize (GskRenderer *renderer)
-{
-  GskGLRenderer *self = GSK_GL_RENDERER (renderer);
-
-  if (self->gl_context == NULL)
-    return;
-
-  gdk_gl_context_make_current (self->gl_context);
-
-  /* We don't need to iterate to destroy the associated GL resources,
-   * as they will be dropped when we finalize the GskGLDriver
-   */
-  ops_reset (&self->op_builder);
-  self->op_builder.programs = NULL;
-
-  g_clear_pointer (&self->programs, gsk_gl_renderer_programs_unref);
-  g_clear_pointer (&self->glyph_cache, gsk_gl_glyph_cache_unref);
-  g_clear_pointer (&self->icon_cache, gsk_gl_icon_cache_unref);
-  g_clear_pointer (&self->atlases, gsk_gl_texture_atlases_unref);
-  gsk_gl_shadow_cache_free (&self->shadow_cache, self->gl_driver);
-
-  g_clear_object (&self->gl_profiler);
-  g_clear_object (&self->gl_driver);
-
-  if (self->gl_context == gdk_gl_context_get_current ())
-    gdk_gl_context_clear_current ();
-
-  g_clear_object (&self->gl_context);
-}
-
-static void
-gsk_gl_renderer_clear_tree (GskGLRenderer *self)
-{
-  if (self->gl_context == NULL)
-    return;
-
-  gdk_gl_context_make_current (self->gl_context);
-
-  ops_reset (&self->op_builder);
-
-#ifdef G_ENABLE_DEBUG
-  int removed_textures = gsk_gl_driver_collect_textures (self->gl_driver);
-  GSK_RENDERER_NOTE (GSK_RENDERER (self), OPENGL, g_message ("Collected: %d textures", removed_textures));
-#else
-  gsk_gl_driver_collect_textures (self->gl_driver);
-#endif
-}
-
-static void
-gsk_gl_renderer_clear (GskGLRenderer *self)
-{
-  GSK_RENDERER_NOTE (GSK_RENDERER (self), OPENGL, g_message ("Clearing viewport"));
-  glClearColor (0, 0, 0, 0);
-  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
-}
-
-static void
-gsk_gl_renderer_setup_render_mode (GskGLRenderer *self)
-{
-  if (self->render_region == NULL)
-    {
-      glDisable (GL_SCISSOR_TEST);
-    }
-  else
-    {
-      GdkSurface *surface = gsk_renderer_get_surface (GSK_RENDERER (self));
-      cairo_rectangle_int_t extents;
-      int surface_height;
-
-      g_assert (cairo_region_num_rectangles (self->render_region) == 1);
-
-      surface_height = gdk_surface_get_height (surface) * self->scale_factor;
-      cairo_region_get_rectangle (self->render_region, 0, &extents);
-
-      glEnable (GL_SCISSOR_TEST);
-      glScissor (extents.x * self->scale_factor,
-                 surface_height - (extents.height * self->scale_factor) - (extents.y * self->scale_factor),
-                 extents.width * self->scale_factor,
-                 extents.height * self->scale_factor);
-    }
-}
-
-static void
-gsk_gl_renderer_add_render_ops (GskGLRenderer   *self,
-                                GskRenderNode   *node,
-                                RenderOpBuilder *builder)
-{
-  /* This can still happen, even if the render nodes are created using
-   * GtkSnapshot, so let's just be safe. */
-  if (node_is_invisible (node))
-    return;
-
-  /* Check whether the render node is entirely out of the current
-   * already transformed clip region */
-  {
-    graphene_rect_t transformed_node_bounds;
-
-    ops_transform_bounds_modelview (builder,
-                                    &node->bounds,
-                                    &transformed_node_bounds);
-
-    if (!graphene_rect_intersects (&builder->current_clip->bounds,
-                                   &transformed_node_bounds))
-      return;
-  }
-
-  switch (gsk_render_node_get_node_type (node))
-    {
-    case GSK_NOT_A_RENDER_NODE:
-      g_assert_not_reached ();
-
-    case GSK_CONTAINER_NODE:
-      {
-        guint i, p;
-
-        for (i = 0, p = gsk_container_node_get_n_children (node); i < p; i ++)
-          {
-            GskRenderNode *child = gsk_container_node_get_child (node, i);
-
-            gsk_gl_renderer_add_render_ops (self, child, builder);
-          }
-      }
-    break;
-
-    case GSK_DEBUG_NODE:
-      {
-        const char *message = gsk_debug_node_get_message (node);
-        if (message)
-          ops_push_debug_group (builder, message);
-        gsk_gl_renderer_add_render_ops (self,
-                                        gsk_debug_node_get_child (node),
-                                        builder);
-        if (message)
-          ops_pop_debug_group (builder);
-      }
-    break;
-
-    case GSK_COLOR_NODE:
-      render_color_node (self, node, builder);
-    break;
-
-    case GSK_TEXTURE_NODE:
-      render_texture_node (self, node, builder);
-    break;
-
-    case GSK_TRANSFORM_NODE:
-      render_transform_node (self, node, builder);
-    break;
-
-    case GSK_OPACITY_NODE:
-      render_opacity_node (self, node, builder);
-    break;
-
-    case GSK_LINEAR_GRADIENT_NODE:
-    case GSK_REPEATING_LINEAR_GRADIENT_NODE:
-      render_linear_gradient_node (self, node, builder);
-    break;
-
-    case GSK_RADIAL_GRADIENT_NODE:
-    case GSK_REPEATING_RADIAL_GRADIENT_NODE:
-      render_radial_gradient_node (self, node, builder);
-    break;
-
-    case GSK_CONIC_GRADIENT_NODE:
-      render_conic_gradient_node (self, node, builder);
-    break;
-
-    case GSK_CLIP_NODE:
-      render_clip_node (self, node, builder);
-    break;
-
-    case GSK_ROUNDED_CLIP_NODE:
-      render_rounded_clip_node (self, node, builder);
-    break;
-
-    case GSK_TEXT_NODE:
-      render_text_node (self, node, builder,
-                        gsk_text_node_get_color (node), FALSE);
-    break;
-
-    case GSK_COLOR_MATRIX_NODE:
-      render_color_matrix_node (self, node, builder);
-    break;
-
-    case GSK_BLUR_NODE:
-      render_blur_node (self, node, builder);
-    break;
-
-    case GSK_INSET_SHADOW_NODE:
-      if (gsk_inset_shadow_node_get_blur_radius (node) > 0)
-        render_inset_shadow_node (self, node, builder);
-      else
-        render_unblurred_inset_shadow_node (self, node, builder);
-    break;
-
-    case GSK_OUTSET_SHADOW_NODE:
-      if (gsk_outset_shadow_node_get_blur_radius (node) > 0)
-        render_outset_shadow_node (self, node, builder);
-      else
-        render_unblurred_outset_shadow_node (self, node, builder);
-    break;
-
-    case GSK_SHADOW_NODE:
-      render_shadow_node (self, node, builder);
-    break;
-
-    case GSK_BORDER_NODE:
-      render_border_node (self, node, builder);
-    break;
-
-    case GSK_CROSS_FADE_NODE:
-      render_cross_fade_node (self, node, builder);
-    break;
-
-    case GSK_BLEND_NODE:
-      render_blend_node (self, node, builder);
-    break;
-
-    case GSK_REPEAT_NODE:
-      render_repeat_node (self, node, builder);
-    break;
-
-    case GSK_GL_SHADER_NODE:
-      render_gl_shader_node (self, node, builder);
-    break;
-
-    case GSK_CAIRO_NODE:
-    default:
-      {
-        render_fallback_node (self, node, builder);
-      }
-    }
-}
-
-static gboolean
-add_offscreen_ops (GskGLRenderer         *self,
-                   RenderOpBuilder       *builder,
-                   const graphene_rect_t *bounds,
-                   GskRenderNode         *child_node,
-                   TextureRegion         *texture_region_out,
-                   gboolean              *is_offscreen,
-                   guint                  flags)
-{
-  const float dx = builder->dx;
-  const float dy = builder->dy;
-  float scaled_width, scaled_height;
-  float scale_x;
-  float scale_y;
-  int render_target;
-  int prev_render_target;
-  graphene_matrix_t prev_projection;
-  graphene_rect_t prev_viewport;
-  graphene_matrix_t item_proj;
-  float prev_opacity = 1.0;
-  int texture_id = 0;
-  int filter;
-  GskTextureKey key;
-  int cached_id;
-  graphene_rect_t viewport;
-
-  if (node_is_invisible (child_node))
-    {
-      /* Just to be safe */
-      *is_offscreen = FALSE;
-      init_full_texture_region (texture_region_out, 0);
-      return FALSE;
-    }
-
-  /* We need the child node as a texture. If it already is one, we don't need to draw
-   * it on a framebuffer of course. */
-  if (gsk_render_node_get_node_type (child_node) == GSK_TEXTURE_NODE &&
-      (flags & FORCE_OFFSCREEN) == 0)
-    {
-      GdkTexture *texture = gsk_texture_node_get_texture (child_node);
-      upload_texture (self, texture, texture_region_out);
-      *is_offscreen = FALSE;
-      return TRUE;
-    }
-
-  if (flags & LINEAR_FILTER)
-    filter = GL_LINEAR;
-  else
-    filter = GL_NEAREST;
-
-  /* Check if we've already cached the drawn texture. */
-  key.pointer = child_node;
-  key.pointer_is_child = TRUE; /* Don't conflict with the child using the cache too */
-  key.parent_rect = *bounds;
-  key.scale_x = builder->scale_x;
-  key.scale_y = builder->scale_y;
-  key.filter = filter;
-  cached_id = gsk_gl_driver_get_texture_for_key (self->gl_driver, &key);
-
-  if (cached_id != 0)
-    {
-      init_full_texture_region (texture_region_out, cached_id);
-      /* We didn't render it offscreen, but hand out an offscreen texture id */
-      *is_offscreen = TRUE;
-      return TRUE;
-    }
-
-  scale_x = builder->scale_x;
-  scale_y = builder->scale_y;
-
-  /* Tweak the scale factor so that the required texture doesn't
-   * exceed the max texture limit. This will render with a lower
-   * resolution, but this is better than clipping.
-   */
-  {
-    const int max_texture_size = gsk_gl_driver_get_max_texture_size (self->gl_driver);
-
-    scaled_width = ceilf (bounds->size.width * scale_x);
-    if (scaled_width > max_texture_size)
-      {
-        scale_x *= (float)max_texture_size / scaled_width;
-        scaled_width = max_texture_size;
-      }
-
-    scaled_height = ceilf (bounds->size.height * scale_y);
-    if (scaled_height > max_texture_size)
-      {
-        scale_y *= (float)max_texture_size / scaled_height;
-        scaled_height = max_texture_size;
-      }
-  }
-
-  gsk_gl_driver_create_render_target (self->gl_driver,
-                                      scaled_width, scaled_height,
-                                      filter, filter,
-                                      &texture_id, &render_target);
-  if (gdk_gl_context_has_debug (self->gl_context))
-    {
-      gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, texture_id,
-                                          "Offscreen<%s> %d",
-                                          g_type_name_from_instance ((GTypeInstance *) child_node),
-                                          texture_id);
-      gdk_gl_context_label_object_printf (self->gl_context, GL_FRAMEBUFFER, render_target,
-                                          "Offscreen<%s> FB %d",
-                                          g_type_name_from_instance ((GTypeInstance *) child_node),
-                                          render_target);
-    }
-
-  ops_transform_bounds_modelview (builder, bounds, &viewport);
-  /* Code above will scale the size with the scale we use in the render ops,
-   * but for the viewport size, we need our own size limited by the texture size */
-  viewport.size.width = scaled_width;
-  viewport.size.height = scaled_height;
-
-  init_projection_matrix (&item_proj, &viewport);
-  prev_render_target = ops_set_render_target (builder, render_target);
-  /* Clear since we use this rendertarget for the first time */
-  ops_begin (builder, OP_CLEAR);
-  prev_projection = ops_set_projection (builder, &item_proj);
-  ops_set_modelview (builder, gsk_transform_scale (NULL, scale_x, scale_y));
-  prev_viewport = ops_set_viewport (builder, &viewport);
-  if (flags & RESET_CLIP)
-    ops_push_clip (builder, &GSK_ROUNDED_RECT_INIT_FROM_RECT (viewport));
-
-  builder->dx = dx;
-  builder->dy = dy;
-
-  prev_opacity = ops_set_opacity (builder, 1.0);
-
-  gsk_gl_renderer_add_render_ops (self, child_node, builder);
-
-#ifdef G_ENABLE_DEBUG
-  if (G_UNLIKELY (flags & DUMP_FRAMEBUFFER))
-    {
-      static int k;
-      ops_dump_framebuffer (builder,
-                            g_strdup_printf ("%s_%p_%d.png",
-                                             g_type_name_from_instance ((GTypeInstance *) child_node),
-                                             child_node,
-                                             k ++),
-                            scaled_width, scaled_height);
-    }
-#endif
-
-  ops_set_opacity (builder, prev_opacity);
-
-  builder->dx = dx;
-  builder->dy = dy;
-
-  if (flags & RESET_CLIP)
-    ops_pop_clip (builder);
-
-  ops_set_viewport (builder, &prev_viewport);
-  ops_pop_modelview (builder);
-  ops_set_projection (builder, &prev_projection);
-  ops_set_render_target (builder, prev_render_target);
-
-  *is_offscreen = TRUE;
-  init_full_texture_region (texture_region_out, texture_id);
-
-  if ((flags & NO_CACHE_PLZ) == 0)
-    gsk_gl_driver_set_texture_for_key (self->gl_driver, &key, texture_id);
-
-  return TRUE;
-}
-
-static void
-gsk_gl_renderer_render_ops (GskGLRenderer *self)
-{
-  const Program *program = NULL;
-  const gsize vertex_data_size = self->op_builder.vertices->len * sizeof (GskQuadVertex);
-  const float *vertex_data = (float *)self->op_builder.vertices->data;
-  OpBufferIter iter;
-  OpKind kind;
-  gpointer ptr;
-  GLuint buffer_id, vao_id;
-
-#if DEBUG_OPS
-  g_print ("============================================\n");
-#endif
-
-  glGenVertexArrays (1, &vao_id);
-  glBindVertexArray (vao_id);
-
-  glGenBuffers (1, &buffer_id);
-  glBindBuffer (GL_ARRAY_BUFFER, buffer_id);
-
-  glBufferData (GL_ARRAY_BUFFER, vertex_data_size, vertex_data, GL_STATIC_DRAW);
-
-  /* 0 = position location */
-  glEnableVertexAttribArray (0);
-  glVertexAttribPointer (0, 2, GL_FLOAT, GL_FALSE,
-                         sizeof (GskQuadVertex),
-                         (void *) G_STRUCT_OFFSET (GskQuadVertex, position));
-  /* 1 = texture coord location */
-  glEnableVertexAttribArray (1);
-  glVertexAttribPointer (1, 2, GL_FLOAT, GL_FALSE,
-                         sizeof (GskQuadVertex),
-                         (void *) G_STRUCT_OFFSET (GskQuadVertex, uv));
-
-  op_buffer_iter_init (&iter, ops_get_buffer (&self->op_builder));
-  while ((ptr = op_buffer_iter_next (&iter, &kind)))
-    {
-      if (kind == OP_NONE)
-        continue;
-
-      if (program == NULL &&
-          kind != OP_PUSH_DEBUG_GROUP &&
-          kind != OP_POP_DEBUG_GROUP &&
-          kind != OP_CHANGE_PROGRAM &&
-          kind != OP_CHANGE_RENDER_TARGET &&
-          kind != OP_CLEAR)
-        continue;
-
-      OP_PRINT ("Op %u: %u", iter.pos - 2, kind);
-
-      switch (kind)
-        {
-        case OP_CHANGE_PROJECTION:
-          apply_projection_op (program, ptr);
-          break;
-
-        case OP_CHANGE_MODELVIEW:
-          apply_modelview_op (program, ptr);
-          break;
-
-        case OP_CHANGE_PROGRAM:
-          {
-            const OpProgram *op = ptr;
-            apply_program_op (program, op);
-            program = op->program;
-            break;
-          }
-
-        case OP_CHANGE_RENDER_TARGET:
-          apply_render_target_op (self, ptr);
-          break;
-
-        case OP_CLEAR:
-          OP_PRINT ("-> CLEAR");
-          glClearColor (0, 0, 0, 0);
-          glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
-          break;
-
-        case OP_CHANGE_VIEWPORT:
-          apply_viewport_op (program, ptr);
-          break;
-
-        case OP_CHANGE_OPACITY:
-          apply_opacity_op (program, ptr);
-          break;
-
-        case OP_CHANGE_COLOR_MATRIX:
-          apply_color_matrix_op (program, ptr);
-          break;
-
-        case OP_CHANGE_COLOR:
-          /*g_assert (program == &self->color_program || program == &self->coloring_program ||*/
-                    /*program == &self->shadow_program);*/
-          apply_color_op (program, ptr);
-          break;
-
-        case OP_CHANGE_BORDER_COLOR:
-          apply_border_color_op (program, ptr);
-          break;
-
-        case OP_CHANGE_CLIP:
-          apply_clip_op (program, ptr);
-          break;
-
-        case OP_CHANGE_SOURCE_TEXTURE:
-          apply_source_texture_op (program, ptr);
-          break;
-
-        case OP_CHANGE_EXTRA_SOURCE_TEXTURE:
-          apply_source_extra_texture_op (program, ptr);
-          break;
-
-        case OP_CHANGE_CROSS_FADE:
-          g_assert (program == &self->programs->cross_fade_program);
-          apply_cross_fade_op (program, ptr);
-          break;
-
-        case OP_CHANGE_BLEND:
-          g_assert (program == &self->programs->blend_program);
-          apply_blend_op (program, ptr);
-          break;
-
-        case OP_CHANGE_LINEAR_GRADIENT:
-          apply_linear_gradient_op (program, ptr);
-          break;
-
-        case OP_CHANGE_RADIAL_GRADIENT:
-          apply_radial_gradient_op (program, ptr);
-          break;
-
-        case OP_CHANGE_CONIC_GRADIENT:
-          apply_conic_gradient_op (program, ptr);
-          break;
-
-        case OP_CHANGE_BLUR:
-          apply_blur_op (program, ptr);
-          break;
-
-        case OP_CHANGE_INSET_SHADOW:
-          apply_inset_shadow_op (program, ptr);
-          break;
-
-        case OP_CHANGE_OUTSET_SHADOW:
-          apply_outset_shadow_op (program, ptr);
-          break;
-
-        case OP_CHANGE_BORDER:
-          apply_border_op (program, ptr);
-          break;
-
-        case OP_CHANGE_BORDER_WIDTH:
-          apply_border_width_op (program, ptr);
-          break;
-
-        case OP_CHANGE_UNBLURRED_OUTSET_SHADOW:
-          apply_unblurred_outset_shadow_op (program, ptr);
-          break;
-
-        case OP_CHANGE_REPEAT:
-          apply_repeat_op (program, ptr);
-          break;
-
-        case OP_CHANGE_GL_SHADER_ARGS:
-          apply_gl_shader_args_op (program, ptr);
-          break;
-
-        case OP_DRAW:
-          {
-            const OpDraw *op = ptr;
-
-            OP_PRINT (" -> draw %ld, size %ld and program %d: %s",
-                      op->vao_offset, op->vao_size, program->index,
-                      program->name ?: "");
-            glDrawArrays (GL_TRIANGLES, op->vao_offset, op->vao_size);
-            break;
-          }
-
-        case OP_DUMP_FRAMEBUFFER:
-          {
-            const OpDumpFrameBuffer *op = ptr;
-
-            dump_framebuffer (op->filename, op->width, op->height);
-            break;
-          }
-
-        case OP_PUSH_DEBUG_GROUP:
-          {
-            const OpDebugGroup *op = ptr;
-            gdk_gl_context_push_debug_group (self->gl_context, op->text);
-            OP_PRINT (" Debug: %s", op->text);
-            break;
-          }
-
-        case OP_POP_DEBUG_GROUP:
-          gdk_gl_context_pop_debug_group (self->gl_context);
-          break;
-
-        case OP_NONE:
-        case OP_LAST:
-        default:
-          g_warn_if_reached ();
-        }
-
-      OP_PRINT ("\n");
-    }
-
-  glDeleteVertexArrays (1, &vao_id);
-  glDeleteBuffers (1, &buffer_id);
-}
-
-static void
-gsk_gl_renderer_do_render (GskRenderer           *renderer,
-                           GskRenderNode         *root,
-                           const graphene_rect_t *viewport,
-                           int                    fbo_id,
-                           int                    scale_factor)
-{
-  GskGLRenderer *self = GSK_GL_RENDERER (renderer);
-  graphene_matrix_t projection;
-#ifdef G_ENABLE_DEBUG
-  GskProfiler *profiler;
-  gint64 gpu_time, cpu_time;
-  gint64 start_time G_GNUC_UNUSED;
-#endif
-  GPtrArray *removed;
-
-#ifdef G_ENABLE_DEBUG
-  profiler = gsk_renderer_get_profiler (renderer);
-#endif
-
-  if (self->gl_context == NULL)
-    {
-      GSK_RENDERER_NOTE (renderer, OPENGL, g_message ("No valid GL context associated to the renderer"));
-      return;
-    }
-
-  g_assert (gsk_gl_driver_in_frame (self->gl_driver));
-
-  removed = g_ptr_array_new ();
-  gsk_gl_texture_atlases_begin_frame (self->atlases, removed);
-  gsk_gl_glyph_cache_begin_frame (self->glyph_cache, self->gl_driver, removed);
-  gsk_gl_icon_cache_begin_frame (self->icon_cache, removed);
-  gsk_gl_shadow_cache_begin_frame (&self->shadow_cache, self->gl_driver);
-  g_ptr_array_unref (removed);
-
-  /* Set up the modelview and projection matrices to fit our viewport */
-  init_projection_matrix (&projection, viewport);
-  ops_set_projection (&self->op_builder, &projection);
-  ops_set_viewport (&self->op_builder, viewport);
-  ops_set_modelview (&self->op_builder, gsk_transform_scale (NULL, scale_factor, scale_factor));
-
-  /* Initial clip is self->render_region! */
-  if (self->render_region != NULL)
-    {
-      graphene_rect_t transformed_render_region;
-      cairo_rectangle_int_t render_extents;
-
-      cairo_region_get_extents (self->render_region, &render_extents);
-
-      ops_transform_bounds_modelview (&self->op_builder,
-                                      &GRAPHENE_RECT_INIT (render_extents.x,
-                                                           render_extents.y,
-                                                           render_extents.width,
-                                                           render_extents.height),
-                                      &transformed_render_region);
-      ops_push_clip (&self->op_builder,
-                     &GSK_ROUNDED_RECT_INIT (transformed_render_region.origin.x,
-                                             transformed_render_region.origin.y,
-                                             transformed_render_region.size.width,
-                                             transformed_render_region.size.height));
-    }
-  else
-    {
-      ops_push_clip (&self->op_builder,
-                     &GSK_ROUNDED_RECT_INIT (viewport->origin.x,
-                                             viewport->origin.y,
-                                             viewport->size.width,
-                                             viewport->size.height));
-    }
-
-  if (fbo_id != 0)
-    ops_set_render_target (&self->op_builder, fbo_id);
-
-  gdk_gl_context_push_debug_group (self->gl_context, "Adding render ops");
-  gsk_gl_renderer_add_render_ops (self, root, &self->op_builder);
-  gdk_gl_context_pop_debug_group (self->gl_context);
-
-  /* We correctly reset the state everywhere */
-  g_assert_cmpint (self->op_builder.current_render_target, ==, fbo_id);
-  ops_pop_modelview (&self->op_builder);
-  ops_pop_clip (&self->op_builder);
-  ops_finish (&self->op_builder);
-
-  /*g_message ("Ops: %u", self->render_ops->len);*/
-
-  /* Now actually draw things... */
-#ifdef G_ENABLE_DEBUG
-  gsk_gl_profiler_begin_gpu_region (self->gl_profiler);
-  gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time);
-#endif
-
-  /* Actually do the rendering */
-  if (fbo_id != 0)
-    glBindFramebuffer (GL_FRAMEBUFFER, fbo_id);
-
-  glViewport (0, 0, ceilf (viewport->size.width), ceilf (viewport->size.height));
-  gsk_gl_renderer_setup_render_mode (self);
-  gsk_gl_renderer_clear (self);
-
-  glEnable (GL_DEPTH_TEST);
-  glDepthFunc (GL_LEQUAL);
-
-  /* Pre-multiplied alpha! */
-  glEnable (GL_BLEND);
-  glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-  glBlendEquation (GL_FUNC_ADD);
-
-  gdk_gl_context_push_debug_group (self->gl_context, "Rendering ops");
-  gsk_gl_renderer_render_ops (self);
-  gdk_gl_context_pop_debug_group (self->gl_context);
-
-#ifdef G_ENABLE_DEBUG
-  gsk_profiler_counter_inc (profiler, self->profile_counters.frames);
-
-  start_time = gsk_profiler_timer_get_start (profiler, self->profile_timers.cpu_time);
-  cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
-  gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time);
-
-  gpu_time = gsk_gl_profiler_end_gpu_region (self->gl_profiler);
-  gsk_profiler_timer_set (profiler, self->profile_timers.gpu_time, gpu_time);
-
-  gsk_profiler_push_samples (profiler);
-
-  gdk_profiler_add_mark (start_time * 1000, cpu_time * 1000, "GL render", "");
-#endif
-}
-
-static GdkTexture *
-gsk_gl_renderer_render_texture (GskRenderer           *renderer,
-                                GskRenderNode         *root,
-                                const graphene_rect_t *viewport)
-{
-  GskGLRenderer *self = GSK_GL_RENDERER (renderer);
-  GdkTexture *texture;
-  int width, height;
-  guint texture_id;
-  guint fbo_id;
-
-  g_return_val_if_fail (self->gl_context != NULL, NULL);
-
-  gdk_gl_context_make_current (self->gl_context);
-  gdk_gl_context_push_debug_group_printf (self->gl_context,
-                                          "Render %s<%p> to texture",
-                                          g_type_name_from_instance ((GTypeInstance *) root),
-                                          root);
-
-  width = ceilf (viewport->size.width);
-  height = ceilf (viewport->size.height);
-
-  self->scale_factor = gdk_surface_get_scale_factor (gsk_renderer_get_surface (renderer));
-
-  /* Prepare our framebuffer */
-  gsk_gl_driver_begin_frame (self->gl_driver);
-  glGenTextures (1, &texture_id);
-  glBindTexture (GL_TEXTURE_2D, texture_id);
-
-  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-
-  if (gdk_gl_context_has_debug (self->gl_context))
-    gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, texture_id,
-                                        "Texture %s<%p> %d",
-                                        g_type_name_from_instance ((GTypeInstance *) root),
-                                        root,
-                                        texture_id);
-
-  if (gdk_gl_context_get_use_es (self->gl_context))
-    glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-  else
-    glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
-
-  glGenFramebuffers (1, &fbo_id);
-  glBindFramebuffer (GL_FRAMEBUFFER, fbo_id);
-
-  if (gdk_gl_context_has_debug (self->gl_context))
-    gdk_gl_context_label_object_printf (self->gl_context, GL_FRAMEBUFFER, fbo_id,
-                                        "FB %s<%p> %d",
-                                        g_type_name_from_instance ((GTypeInstance *) root),
-                                        root,
-                                        fbo_id);
-  glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_id, 0);
-
-  /* Render the actual scene */
-  gsk_gl_renderer_do_render (renderer, root, viewport, fbo_id, 1);
-
-  glDeleteFramebuffers (1, &fbo_id);
-
-
-  /* Render the now drawn framebuffer y-flipped so it's as GdkGLTexture expects it to be */
-  {
-    guint final_texture_id, final_fbo_id;
-    graphene_matrix_t m;
-
-    ops_reset (&self->op_builder);
-
-    glGenFramebuffers (1, &final_fbo_id);
-    glBindFramebuffer (GL_FRAMEBUFFER, final_fbo_id);
-    glGenTextures (1, &final_texture_id);
-    glBindTexture (GL_TEXTURE_2D, final_texture_id);
-
-    if (gdk_gl_context_get_use_es (self->gl_context))
-      glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-    else
-      glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
-
-    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-
-    glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, final_texture_id, 0);
-    g_assert_cmphex (glCheckFramebufferStatus (GL_FRAMEBUFFER), ==, GL_FRAMEBUFFER_COMPLETE);
-
-    ops_set_render_target (&self->op_builder, final_fbo_id);
-    ops_push_clip (&self->op_builder, &GSK_ROUNDED_RECT_INIT (0, 0, width, height));
-    ops_set_program (&self->op_builder, &self->programs->blit_program);
-
-    ops_begin (&self->op_builder, OP_CLEAR);
-    ops_set_texture (&self->op_builder, texture_id);
-    ops_set_modelview (&self->op_builder, NULL);
-    ops_set_viewport (&self->op_builder, &GRAPHENE_RECT_INIT (0, 0, width, height));
-    init_projection_matrix (&m, &GRAPHENE_RECT_INIT (0, 0, width, height));
-    graphene_matrix_scale (&m, 1, -1, 1); /* Undo the scale init_projection_matrix() does again */
-    ops_set_projection (&self->op_builder, &m);
-
-    fill_vertex_data (ops_draw (&self->op_builder, NULL),
-                      0, 0, width, height);
-    ops_pop_clip (&self->op_builder);
-    gsk_gl_renderer_render_ops (self);
-
-    ops_finish (&self->op_builder);
-
-    glDeleteTextures (1, &texture_id);
-
-    texture_id = final_texture_id;
-  }
-
-  texture = gdk_gl_texture_new (self->gl_context,
-                                texture_id,
-                                width, height,
-                                NULL, NULL);
-
-  gsk_gl_driver_end_frame (self->gl_driver);
-
-  gdk_gl_context_pop_debug_group (self->gl_context);
-
-  gsk_gl_renderer_clear_tree (self);
-  return texture;
-}
-
-static void
-gsk_gl_renderer_render (GskRenderer          *renderer,
-                        GskRenderNode        *root,
-                        const cairo_region_t *update_area)
-{
-  GskGLRenderer *self = GSK_GL_RENDERER (renderer);
-  graphene_rect_t viewport;
-  const cairo_region_t *damage;
-  GdkRectangle whole_surface;
-  GdkSurface *surface;
-
-  if (self->gl_context == NULL)
-    return;
-
-  surface = gsk_renderer_get_surface (renderer);
-  self->scale_factor = gdk_surface_get_scale_factor (surface);
-
-  gdk_gl_context_make_current (self->gl_context);
-  gdk_gl_context_push_debug_group_printf (self->gl_context,
-                                          "Render root node %p", root);
-
-  whole_surface = (GdkRectangle) {
-                      0, 0,
-                      gdk_surface_get_width (surface) * self->scale_factor,
-                      gdk_surface_get_height (surface) * self->scale_factor
-                  };
-
-  gdk_draw_context_begin_frame (GDK_DRAW_CONTEXT (self->gl_context),
-                                update_area);
-
-  damage = gdk_draw_context_get_frame_region (GDK_DRAW_CONTEXT (self->gl_context));
-
-  if (cairo_region_contains_rectangle (damage, &whole_surface) == CAIRO_REGION_OVERLAP_IN)
-    {
-      self->render_region = NULL;
-    }
-  else
-    {
-      GdkRectangle extents;
-
-      cairo_region_get_extents (damage, &extents);
-
-      if (gdk_rectangle_equal (&extents, &whole_surface))
-        self->render_region = NULL;
-      else
-        self->render_region = cairo_region_create_rectangle (&extents);
-    }
-
-  gdk_gl_context_make_current (self->gl_context);
-
-  viewport.origin.x = 0;
-  viewport.origin.y = 0;
-  viewport.size.width = whole_surface.width;
-  viewport.size.height = whole_surface.height;
-
-  gsk_gl_driver_begin_frame (self->gl_driver);
-  gsk_gl_renderer_do_render (renderer, root, &viewport, 0, self->scale_factor);
-  gsk_gl_driver_end_frame (self->gl_driver);
-
-  gsk_gl_renderer_clear_tree (self);
-
-  gdk_draw_context_end_frame (GDK_DRAW_CONTEXT (self->gl_context));
-  gdk_gl_context_make_current (self->gl_context);
-
-  gdk_gl_context_pop_debug_group (self->gl_context);
-
-  g_clear_pointer (&self->render_region, cairo_region_destroy);
-}
-
-static void
-gsk_gl_renderer_class_init (GskGLRendererClass *klass)
-{
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-  GskRendererClass *renderer_class = GSK_RENDERER_CLASS (klass);
-
-  gobject_class->dispose = gsk_gl_renderer_dispose;
-
-  renderer_class->realize = gsk_gl_renderer_realize;
-  renderer_class->unrealize = gsk_gl_renderer_unrealize;
-  renderer_class->render = gsk_gl_renderer_render;
-  renderer_class->render_texture = gsk_gl_renderer_render_texture;
-}
-
-static void
-gsk_gl_renderer_init (GskGLRenderer *self)
-{
-  gsk_ensure_resources ();
-
-  ops_init (&self->op_builder);
-  self->op_builder.renderer = self;
-
-#ifdef G_ENABLE_DEBUG
-  {
-    GskProfiler *profiler = gsk_renderer_get_profiler (GSK_RENDERER (self));
-
-    self->profile_counters.frames = gsk_profiler_add_counter (profiler, "frames", "Frames", FALSE);
-
-    self->profile_timers.cpu_time = gsk_profiler_add_timer (profiler, "cpu-time", "CPU time", FALSE, TRUE);
-    self->profile_timers.gpu_time = gsk_profiler_add_timer (profiler, "gpu-time", "GPU time", FALSE, TRUE);
-  }
-#endif
-}
-
-/**
- * gsk_gl_renderer_new:
- *
- * Creates a new `GskRenderer` using OpenGL.
- *
- * Returns: a new GL renderer
- */
-GskRenderer *
-gsk_gl_renderer_new (void)
-{
-  return g_object_new (GSK_TYPE_GL_RENDERER, NULL);
-}
diff --git a/gsk/gl/gskglrenderer.h b/gsk/gl/gskglrenderer.h
deleted file mode 100644 (file)
index 13466fc..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright Â© 2016  Endless 
- *             2018  Timm Bäder <mail@baedert.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- *
- * Authors: Timm Bäder <mail@baedert.org>
- */
-
-#ifndef __GSK_GL_RENDERER_H__
-#define __GSK_GL_RENDERER_H__
-
-#include <gsk/gskrenderer.h>
-
-G_BEGIN_DECLS
-
-#define GSK_TYPE_GL_RENDERER (gsk_gl_renderer_get_type ())
-
-#define GSK_GL_RENDERER(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_GL_RENDERER, GskGLRenderer))
-#define GSK_IS_GL_RENDERER(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_GL_RENDERER))
-#define GSK_GL_RENDERER_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_GL_RENDERER, GskGLRendererClass))
-#define GSK_IS_GL_RENDERER_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_GL_RENDERER))
-#define GSK_GL_RENDERER_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_GL_RENDERER, GskGLRendererClass))
-
-/**
- * GskGLRenderer:
- *
- * A GSK renderer that is using OpenGL.
- */
-typedef struct _GskGLRenderer                   GskGLRenderer;
-typedef struct _GskGLRendererClass              GskGLRendererClass;
-
-GDK_AVAILABLE_IN_ALL
-GType                   gsk_gl_renderer_get_type                (void) G_GNUC_CONST;
-
-GDK_AVAILABLE_IN_ALL
-GskRenderer *           gsk_gl_renderer_new                     (void);
-
-G_END_DECLS
-
-#endif /* __GSK_GL_RENDERER_H__ */
diff --git a/gsk/gl/gskglrendererprivate.h b/gsk/gl/gskglrendererprivate.h
deleted file mode 100644 (file)
index 924ee18..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef __GSK_GL_RENDERER_PRIVATE_H__
-#define __GSK_GL_RENDERER_PRIVATE_H__
-
-#include "gskglrenderer.h"
-
-G_BEGIN_DECLS
-
-gboolean gsk_gl_renderer_try_compile_gl_shader (GskGLRenderer    *self,
-                                                GskGLShader      *shader,
-                                                GError          **error);
-
-G_END_DECLS
-
-#endif /* __GSK_GL_RENDERER_PRIVATE_H__ */
diff --git a/gsk/gl/gskglrenderops.c b/gsk/gl/gskglrenderops.c
deleted file mode 100644 (file)
index 36f7e37..0000000
+++ /dev/null
@@ -1,976 +0,0 @@
-#include "gskglrenderopsprivate.h"
-#include "gsktransform.h"
-
-typedef struct
-{
-  GskRoundedRect rect;
-  bool is_rectilinear;
-} ClipStackEntry;
-
-static inline gboolean
-rect_equal (const graphene_rect_t *a,
-            const graphene_rect_t *b)
-{
-  return memcmp (a, b, sizeof (graphene_rect_t)) == 0;
-}
-
-static inline bool G_GNUC_PURE
-rounded_rect_equal (const GskRoundedRect *r1,
-                    const GskRoundedRect *r2)
-{
-  if (r1 == r2)
-      return true;
-
-  if (!r1)
-    return false;
-
-  if (r1->bounds.origin.x != r2->bounds.origin.x ||
-      r1->bounds.origin.y != r2->bounds.origin.y ||
-      r1->bounds.size.width != r2->bounds.size.width ||
-      r1->bounds.size.height != r2->bounds.size.height)
-    return false;
-
-  for (int i = 0; i < 4; i ++)
-    if (r1->corner[i].width != r2->corner[i].width ||
-        r1->corner[i].height != r2->corner[i].height)
-      return false;
-
-  return true;
-}
-
-static inline gboolean G_GNUC_PURE
-rounded_rect_corners_equal (const GskRoundedRect *r1,
-                            const GskRoundedRect *r2)
-{
-  int i;
-
-  if (!r1)
-    return FALSE;
-
-  for (i = 0; i < 4; i ++)
-    if (r1->corner[i].width != r2->corner[i].width ||
-        r1->corner[i].height != r2->corner[i].height)
-      return FALSE;
-
-  return TRUE;
-}
-
-static inline ProgramState *
-get_current_program_state (RenderOpBuilder *builder)
-{
-  if (!builder->current_program)
-    return NULL;
-
-  return &builder->current_program->state;
-}
-
-void
-ops_finish (RenderOpBuilder *builder)
-{
-  if (builder->mv_stack)
-    g_array_free (builder->mv_stack, TRUE);
-  builder->mv_stack = NULL;
-
-  if (builder->clip_stack)
-    g_array_free (builder->clip_stack, TRUE);
-  builder->clip_stack = NULL;
-
-  builder->dx = 0;
-  builder->dy = 0;
-  builder->scale_x = 1;
-  builder->scale_y = 1;
-  builder->current_modelview = NULL;
-  builder->current_clip = NULL;
-  builder->clip_is_rectilinear = TRUE;
-  builder->current_render_target = 0;
-  builder->current_texture = 0;
-  builder->current_program = NULL;
-  graphene_matrix_init_identity (&builder->current_projection);
-  builder->current_viewport = GRAPHENE_RECT_INIT (0, 0, 0, 0);
-}
-
-/* Debugging only! */
-void
-ops_dump_framebuffer (RenderOpBuilder *builder,
-                      const char      *filename,
-                      int              width,
-                      int              height)
-{
-  OpDumpFrameBuffer *op;
-
-  op = ops_begin (builder, OP_DUMP_FRAMEBUFFER);
-  op->filename = g_strdup (filename);
-  op->width = width;
-  op->height = height;
-}
-
-void
-ops_push_debug_group (RenderOpBuilder *builder,
-                      const char      *text)
-{
-  OpDebugGroup *op;
-
-  op = ops_begin (builder, OP_PUSH_DEBUG_GROUP);
-  strncpy (op->text, text, sizeof(op->text) - 1);
-  op->text[sizeof(op->text) - 1] = 0; /* Ensure zero terminated */
-}
-
-void
-ops_pop_debug_group (RenderOpBuilder *builder)
-{
-  ops_begin (builder, OP_POP_DEBUG_GROUP);
-}
-
-static void
-extract_matrix_metadata (GskTransform      *transform,
-                         OpsMatrixMetadata *md)
-{
-  float dummy;
-
-  switch (gsk_transform_get_category (transform))
-    {
-    case GSK_TRANSFORM_CATEGORY_IDENTITY:
-    case GSK_TRANSFORM_CATEGORY_2D_TRANSLATE:
-      md->scale_x = 1;
-      md->scale_y = 1;
-    break;
-
-    case GSK_TRANSFORM_CATEGORY_2D_AFFINE:
-      gsk_transform_to_affine (transform,
-                               &md->scale_x, &md->scale_y,
-                               &dummy, &dummy);
-    break;
-
-    case GSK_TRANSFORM_CATEGORY_UNKNOWN:
-    case GSK_TRANSFORM_CATEGORY_ANY:
-    case GSK_TRANSFORM_CATEGORY_3D:
-    case GSK_TRANSFORM_CATEGORY_2D:
-      {
-        graphene_vec3_t col1;
-        graphene_vec3_t col2;
-        graphene_matrix_t m;
-
-        gsk_transform_to_matrix (transform, &m);
-
-        /* TODO: 90% sure this is incorrect. But we should never hit this code
-         * path anyway. */
-        graphene_vec3_init (&col1,
-                            graphene_matrix_get_value (&m, 0, 0),
-                            graphene_matrix_get_value (&m, 1, 0),
-                            graphene_matrix_get_value (&m, 2, 0));
-
-        graphene_vec3_init (&col2,
-                            graphene_matrix_get_value (&m, 0, 1),
-                            graphene_matrix_get_value (&m, 1, 1),
-                            graphene_matrix_get_value (&m, 2, 1));
-
-        md->scale_x = graphene_vec3_length (&col1);
-        md->scale_y = graphene_vec3_length (&col2);
-      }
-    break;
-    default:
-      {}
-    }
-}
-
-void
-ops_transform_bounds_modelview (const RenderOpBuilder *builder,
-                                const graphene_rect_t *src,
-                                graphene_rect_t       *dst)
-{
-  graphene_rect_t r = *src;
-
-  g_assert (builder->mv_stack != NULL);
-  g_assert (builder->mv_stack->len >= 1);
-
-  r.origin.x += builder->dx;
-  r.origin.y += builder->dy;
-
-  gsk_transform_transform_bounds (builder->current_modelview, &r, dst);
-}
-
-void
-ops_init (RenderOpBuilder *builder)
-{
-  memset (builder, 0, sizeof (*builder));
-
-  builder->current_opacity = 1.0f;
-
-  op_buffer_init (&builder->render_ops);
-  builder->vertices = g_array_new (FALSE, TRUE, sizeof (GskQuadVertex));
-}
-
-void
-ops_free (RenderOpBuilder *builder)
-{
-  g_array_unref (builder->vertices);
-  op_buffer_destroy (&builder->render_ops);
-}
-
-void
-ops_set_program (RenderOpBuilder *builder,
-                 Program         *program)
-{
-  OpProgram *op;
-
-  if (builder->current_program == program)
-    return;
-
-  op = ops_begin (builder, OP_CHANGE_PROGRAM);
-  op->program = program;
-
-  builder->current_program = program;
-}
-
-void
-ops_push_clip (RenderOpBuilder      *self,
-               const GskRoundedRect *clip)
-{
-  ClipStackEntry entry;
-
-  if (G_UNLIKELY (self->clip_stack == NULL))
-    self->clip_stack = g_array_new (FALSE, TRUE, sizeof (ClipStackEntry));
-
-  g_assert (self->clip_stack != NULL);
-
-  entry.rect = *clip;
-  entry.is_rectilinear = gsk_rounded_rect_is_rectilinear (clip);
-  g_array_append_val (self->clip_stack, entry);
-  self->current_clip = &g_array_index (self->clip_stack, ClipStackEntry, self->clip_stack->len - 1).rect;
-  self->clip_is_rectilinear = entry.is_rectilinear;
-}
-
-void
-ops_pop_clip (RenderOpBuilder *self)
-{
-  const ClipStackEntry *head;
-
-  g_assert (self->clip_stack);
-  g_assert (self->clip_stack->len >= 1);
-
-  self->clip_stack->len --;
-  head = &g_array_index (self->clip_stack, ClipStackEntry, self->clip_stack->len - 1);
-
-  if (self->clip_stack->len >= 1)
-    {
-      self->current_clip = &head->rect;
-      self->clip_is_rectilinear = head->is_rectilinear;
-    }
-  else
-    {
-      self->current_clip = NULL;
-      self->clip_is_rectilinear = TRUE;
-    }
-}
-
-gboolean
-ops_has_clip (RenderOpBuilder *self)
-{
-  return self->clip_stack != NULL &&
-         self->clip_stack->len > 1;
-}
-
-/**
- * ops_set_modelview:
- * @builder
- * @transform: (transfer full): The new modelview transform
- *
- * This sets the modelview to the given one without looking at the
- * one that's currently set */
-void
-ops_set_modelview (RenderOpBuilder *builder,
-                   GskTransform    *transform)
-{
-  MatrixStackEntry *entry;
-
-  if (G_UNLIKELY (builder->mv_stack == NULL))
-    builder->mv_stack = g_array_new (FALSE, TRUE, sizeof (MatrixStackEntry));
-
-  g_assert (builder->mv_stack != NULL);
-
-  g_array_set_size (builder->mv_stack, builder->mv_stack->len + 1);
-  entry = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
-
-  entry->transform = transform;
-
-  entry->metadata.dx_before = builder->dx;
-  entry->metadata.dy_before = builder->dy;
-  extract_matrix_metadata (entry->transform, &entry->metadata);
-
-  builder->dx = 0;
-  builder->dy = 0;
-  builder->current_modelview = entry->transform;
-  builder->scale_x = entry->metadata.scale_x;
-  builder->scale_y = entry->metadata.scale_y;
-}
-
-/* This sets the given modelview to the one we get when multiplying
- * the given modelview with the current one. */
-void
-ops_push_modelview (RenderOpBuilder *builder,
-                    GskTransform    *transform)
-{
-  MatrixStackEntry *entry;
-
-  if (G_UNLIKELY (builder->mv_stack == NULL))
-    builder->mv_stack = g_array_new (FALSE, TRUE, sizeof (MatrixStackEntry));
-
-  g_assert (builder->mv_stack != NULL);
-
-  g_array_set_size (builder->mv_stack, builder->mv_stack->len + 1);
-  entry = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
-
-  if (G_LIKELY (builder->mv_stack->len >= 2))
-    {
-      const MatrixStackEntry *cur;
-      GskTransform *t = NULL;
-
-      cur = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 2);
-      /* Multiply given matrix with current modelview */
-
-      t = gsk_transform_translate (gsk_transform_ref (cur->transform),
-                                   &(graphene_point_t) { builder->dx, builder->dy});
-      t = gsk_transform_transform (t, transform);
-      entry->transform = t;
-    }
-  else
-    {
-      entry->transform = gsk_transform_ref (transform);
-    }
-
-  entry->metadata.dx_before = builder->dx;
-  entry->metadata.dy_before = builder->dy;
-  extract_matrix_metadata (entry->transform, &entry->metadata);
-
-  builder->dx = 0;
-  builder->dy = 0;
-  builder->scale_x = entry->metadata.scale_x;
-  builder->scale_y = entry->metadata.scale_y;
-  builder->current_modelview = entry->transform;
-}
-
-void
-ops_pop_modelview (RenderOpBuilder *builder)
-{
-  const MatrixStackEntry *head;
-
-  g_assert (builder->mv_stack);
-  g_assert (builder->mv_stack->len >= 1);
-
-  head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
-  builder->dx = head->metadata.dx_before;
-  builder->dy = head->metadata.dy_before;
-  gsk_transform_unref (head->transform);
-
-  builder->mv_stack->len --;
-  head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
-
-  if (builder->mv_stack->len >= 1)
-    {
-      builder->scale_x = head->metadata.scale_x;
-      builder->scale_y = head->metadata.scale_y;
-      builder->current_modelview = head->transform;
-    }
-  else
-    {
-      builder->current_modelview = NULL;
-    }
-}
-
-graphene_matrix_t
-ops_set_projection (RenderOpBuilder         *builder,
-                    const graphene_matrix_t *projection)
-{
-  graphene_matrix_t prev_mv;
-
-  prev_mv = builder->current_projection;
-  builder->current_projection = *projection;
-
-  return prev_mv;
-}
-
-graphene_rect_t
-ops_set_viewport (RenderOpBuilder       *builder,
-                  const graphene_rect_t *viewport)
-{
-  ProgramState *current_program_state = get_current_program_state (builder);
-  OpViewport *op;
-  graphene_rect_t prev_viewport;
-
-  if (rect_equal (&builder->current_viewport, viewport))
-    return *viewport;
-
-  op = ops_begin (builder, OP_CHANGE_VIEWPORT);
-  op->viewport = *viewport;
-
-  if (current_program_state != NULL)
-    current_program_state->viewport = *viewport;
-
-  prev_viewport = builder->current_viewport;
-  builder->current_viewport = *viewport;
-
-  return prev_viewport;
-}
-
-void
-ops_set_texture (RenderOpBuilder *builder,
-                 int              texture_id)
-{
-  OpTexture *op;
-
-  if (builder->current_texture == texture_id)
-    return;
-
-  op = ops_begin (builder, OP_CHANGE_SOURCE_TEXTURE);
-  op->texture_id = texture_id;
-  builder->current_texture = texture_id;
-}
-
-void
-ops_set_extra_texture (RenderOpBuilder *builder,
-                       int              texture_id,
-                       int              idx)
-{
-  OpExtraTexture *op;
-
-  op = ops_begin (builder, OP_CHANGE_EXTRA_SOURCE_TEXTURE);
-  op->texture_id = texture_id;
-  op->idx = idx;
-}
-
-int
-ops_set_render_target (RenderOpBuilder *builder,
-                       int              render_target_id)
-{
-  OpRenderTarget *op;
-  int prev_render_target;
-
-  if (builder->current_render_target == render_target_id)
-    return render_target_id;
-
-  prev_render_target = builder->current_render_target;
-
-  if (!(op = op_buffer_peek_tail_checked (&builder->render_ops, OP_CHANGE_RENDER_TARGET)))
-    op = op_buffer_add (&builder->render_ops, OP_CHANGE_RENDER_TARGET);
-
-  op->render_target_id = render_target_id;
-
-  builder->current_render_target = render_target_id;
-
-  return prev_render_target;
-}
-
-float
-ops_set_opacity (RenderOpBuilder *builder,
-                 float            opacity)
-{
-  float prev_opacity;
-
-  if (builder->current_opacity == opacity)
-    return opacity;
-
-  prev_opacity = builder->current_opacity;
-  builder->current_opacity = opacity;
-
-  return prev_opacity;
-}
-
-void
-ops_set_color (RenderOpBuilder *builder,
-               const GdkRGBA   *color)
-{
-  ProgramState *current_program_state = get_current_program_state (builder);
-  OpColor *op;
-
-  if (gdk_rgba_equal (color, &current_program_state->color))
-    return;
-
-  current_program_state->color = *color;
-
-  op = ops_begin (builder, OP_CHANGE_COLOR);
-  op->rgba = color;
-}
-
-void
-ops_set_gl_shader_args (RenderOpBuilder       *builder,
-                        GskGLShader           *shader,
-                        float                  width,
-                        float                  height,
-                        const guchar          *uniform_data)
-{
-  ProgramState *current_program_state = get_current_program_state (builder);
-  OpGLShader *op;
-  gsize args_size = gsk_gl_shader_get_args_size (shader);
-
-  if (current_program_state)
-    {
-      if (current_program_state->gl_shader.width == width &&
-          current_program_state->gl_shader.height == height &&
-          current_program_state->gl_shader.uniform_data_len == args_size &&
-          memcmp (current_program_state->gl_shader.uniform_data, uniform_data, args_size) == 0)
-        return;
-
-      current_program_state->gl_shader.width = width;
-      current_program_state->gl_shader.height = height;
-      if (args_size > sizeof (current_program_state->gl_shader.uniform_data))
-        current_program_state->gl_shader.uniform_data_len = 0;
-      else
-        {
-          current_program_state->gl_shader.uniform_data_len = args_size;
-          memcpy (current_program_state->gl_shader.uniform_data, uniform_data, args_size);
-        }
-    }
-
-  op = ops_begin (builder, OP_CHANGE_GL_SHADER_ARGS);
-  op->shader = shader;
-  op->size[0] = width;
-  op->size[1] = height;
-  op->uniform_data = uniform_data;
-}
-
-void
-ops_set_color_matrix (RenderOpBuilder         *builder,
-                      const graphene_matrix_t *matrix,
-                      const graphene_vec4_t   *offset)
-{
-  ProgramState *current_program_state = get_current_program_state (builder);
-  const bool offset_equal = graphene_vec4_equal (offset, &current_program_state->color_matrix.offset);
-  const bool matrix_equal = graphene_matrix_equal_fast (matrix,
-                                                        &current_program_state->color_matrix.matrix);
-  OpColorMatrix *op;
-
-  if (offset_equal && matrix_equal)
-    return;
-
-  op = ops_begin (builder, OP_CHANGE_COLOR_MATRIX);
-
-  if (!matrix_equal)
-    {
-      current_program_state->color_matrix.matrix = *matrix;
-      op->matrix.value = matrix;
-      op->matrix.send = TRUE;
-    }
-  else
-    op->matrix.send = FALSE;
-
-  if (!offset_equal)
-    {
-      current_program_state->color_matrix.offset = *offset;
-      op->offset.value = offset;
-      op->offset.send = TRUE;
-    }
-  else
-    op->offset.send = FALSE;
-}
-
-void
-ops_set_border (RenderOpBuilder      *builder,
-                const GskRoundedRect *outline)
-{
-  ProgramState *current_program_state = get_current_program_state (builder);
-  OpBorder *op;
-
-  if (memcmp (&current_program_state->border.outline,
-              outline, sizeof (GskRoundedRect)) == 0)
-    return;
-
-  current_program_state->border.outline = *outline;
-
-  op = ops_begin (builder, OP_CHANGE_BORDER);
-  op->outline = *outline;
-}
-
-void
-ops_set_border_width (RenderOpBuilder *builder,
-                      const float     *widths)
-{
-  ProgramState *current_program_state = get_current_program_state (builder);
-  OpBorder *op;
-
-  g_assert (current_program_state);
-
-  if (memcmp (current_program_state->border.widths,
-              widths, sizeof (float) * 4) == 0)
-    return;
-
-  memcpy (&current_program_state->border.widths,
-          widths, sizeof (float) * 4);
-
-  op = ops_begin (builder, OP_CHANGE_BORDER_WIDTH);
-  op->widths[0] = widths[0];
-  op->widths[1] = widths[1];
-  op->widths[2] = widths[2];
-  op->widths[3] = widths[3];
-}
-
-void
-ops_set_border_color (RenderOpBuilder *builder,
-                      const GdkRGBA   *color)
-{
-  ProgramState *current_program_state = get_current_program_state (builder);
-  OpBorder *op;
-
-  if (gdk_rgba_equal (color, &current_program_state->border.color))
-    return;
-
-  op = op_buffer_add (&builder->render_ops, OP_CHANGE_BORDER_COLOR);
-  op->color = color;
-
-  current_program_state->border.color = *color;
-}
-
-GskQuadVertex *
-ops_draw (RenderOpBuilder     *builder,
-          const GskQuadVertex  vertex_data[GL_N_VERTICES])
-{
-  ProgramState *program_state = get_current_program_state (builder);
-  OpDraw *op;
-
-  if (memcmp (&builder->current_projection, &program_state->projection, sizeof (graphene_matrix_t)) != 0)
-    {
-      OpMatrix *opm;
-
-      opm = ops_begin (builder, OP_CHANGE_PROJECTION);
-      opm->matrix = builder->current_projection;
-      program_state->projection = builder->current_projection;
-    }
-
-  if (program_state->modelview == NULL ||
-      !gsk_transform_equal (builder->current_modelview, program_state->modelview))
-    {
-      OpMatrix *opm;
-
-      opm = ops_begin (builder, OP_CHANGE_MODELVIEW);
-      gsk_transform_to_matrix (builder->current_modelview, &opm->matrix);
-      gsk_transform_unref (program_state->modelview);
-      program_state->modelview = gsk_transform_ref (builder->current_modelview);
-    }
-
-  if (!rect_equal (&builder->current_viewport, &program_state->viewport))
-    {
-      OpViewport *opv;
-
-      opv = ops_begin (builder, OP_CHANGE_VIEWPORT);
-      opv->viewport = builder->current_viewport;
-      program_state->viewport = builder->current_viewport;
-    }
-
-  if (!rounded_rect_equal (builder->current_clip, &program_state->clip))
-    {
-      OpClip *opc;
-
-      opc = ops_begin (builder, OP_CHANGE_CLIP);
-      opc->clip = *builder->current_clip;
-      opc->send_corners = !rounded_rect_corners_equal (builder->current_clip, &program_state->clip);
-      program_state->clip = *builder->current_clip;
-    }
-
-  if (program_state->opacity != builder->current_opacity)
-    {
-      OpOpacity *opo;
-
-      opo = ops_begin (builder, OP_CHANGE_OPACITY);
-      opo->opacity = builder->current_opacity;
-      program_state->opacity = builder->current_opacity;
-    }
-
-  /* TODO: Did the additions above break the following optimization? */
-  if ((op = op_buffer_peek_tail_checked (&builder->render_ops, OP_DRAW)))
-    {
-      op->vao_size += GL_N_VERTICES;
-    }
-  else
-    {
-      op = op_buffer_add (&builder->render_ops, OP_DRAW);
-      op->vao_offset = builder->vertices->len;
-      op->vao_size = GL_N_VERTICES;
-    }
-
-  if (vertex_data)
-    {
-      g_array_append_vals (builder->vertices, vertex_data, GL_N_VERTICES);
-      return NULL; /* Better not use this on the caller side */
-    }
-
-  g_array_set_size (builder->vertices, builder->vertices->len + GL_N_VERTICES);
-  return &g_array_index (builder->vertices, GskQuadVertex, builder->vertices->len - GL_N_VERTICES);
-}
-
-/* The offset is only valid for the current modelview.
- * Setting a new modelview will add the offset to that matrix
- * and reset the internal offset to 0. */
-void
-ops_offset (RenderOpBuilder *builder,
-            float            x,
-            float            y)
-{
-  builder->dx += x;
-  builder->dy += y;
-}
-
-gpointer
-ops_begin (RenderOpBuilder *builder,
-           OpKind           kind)
-{
-  return op_buffer_add (&builder->render_ops, kind);
-}
-
-void
-ops_reset (RenderOpBuilder *builder)
-{
-  op_buffer_clear (&builder->render_ops);
-  g_array_set_size (builder->vertices, 0);
-}
-
-OpBuffer *
-ops_get_buffer (RenderOpBuilder *builder)
-{
-  return &builder->render_ops;
-}
-
-void
-ops_set_inset_shadow (RenderOpBuilder      *self,
-                      const GskRoundedRect  outline,
-                      float                 spread,
-                      const GdkRGBA        *color,
-                      float                 dx,
-                      float                 dy)
-{
-  ProgramState *current_program_state = get_current_program_state (self);
-  OpShadow *op;
-
-  g_assert (current_program_state);
-
-  op = ops_begin (self, OP_CHANGE_INSET_SHADOW);
-
-  if (!rounded_rect_equal (&outline, &current_program_state->inset_shadow.outline))
-    {
-      op->outline.value = outline;
-      op->outline.send = TRUE;
-      op->outline.send_corners = !rounded_rect_corners_equal (&current_program_state->inset_shadow.outline,
-                                                              &outline);
-      current_program_state->inset_shadow.outline = outline;
-    }
-  else
-    op->outline.send = FALSE;
-
-  if (spread != current_program_state->inset_shadow.spread)
-    {
-      op->spread.value = spread;
-      op->spread.send = TRUE;
-
-      current_program_state->inset_shadow.spread = spread;
-    }
-  else
-    op->spread.send = FALSE;
-
-  if (!gdk_rgba_equal (color, &current_program_state->inset_shadow.color))
-    {
-      op->color.value = color;
-      op->color.send = TRUE;
-
-      current_program_state->inset_shadow.color = *color;
-    }
-  else
-    op->color.send = FALSE;
-
-  if (dx != current_program_state->inset_shadow.dx ||
-      dy != current_program_state->inset_shadow.dy)
-    {
-      op->offset.value[0] = dx;
-      op->offset.value[1] = dy;
-      op->offset.send = TRUE;
-
-      current_program_state->inset_shadow.dx = dx;
-      current_program_state->inset_shadow.dy = dy;
-    }
-  else
-    op->offset.send = FALSE;
-
-  if (!op->outline.send &&
-      !op->spread.send &&
-      !op->offset.send &&
-      !op->color.send)
-    {
-      op_buffer_pop_tail (&self->render_ops);
-    }
-}
-void
-ops_set_unblurred_outset_shadow (RenderOpBuilder      *self,
-                                 const GskRoundedRect  outline,
-                                 float                 spread,
-                                 const GdkRGBA        *color,
-                                 float                 dx,
-                                 float                 dy)
-{
-  ProgramState *current_program_state = get_current_program_state (self);
-  OpShadow *op;
-
-  g_assert (current_program_state);
-
-  op = ops_begin (self, OP_CHANGE_UNBLURRED_OUTSET_SHADOW);
-
-  if (!rounded_rect_equal (&outline, &current_program_state->unblurred_outset_shadow.outline))
-    {
-      op->outline.value = outline;
-      op->outline.send = TRUE;
-      op->outline.send_corners = !rounded_rect_corners_equal (&current_program_state->unblurred_outset_shadow.outline,
-                                                              &outline);
-      current_program_state->unblurred_outset_shadow.outline = outline;
-    }
-  else
-    op->outline.send = FALSE;
-
-  if (spread != current_program_state->unblurred_outset_shadow.spread)
-    {
-      op->spread.value = spread;
-      op->spread.send = TRUE;
-
-      current_program_state->unblurred_outset_shadow.spread = spread;
-    }
-  else
-    op->spread.send = FALSE;
-
-  if (!gdk_rgba_equal (color, &current_program_state->unblurred_outset_shadow.color))
-    {
-      op->color.value = color;
-      op->color.send = TRUE;
-
-      current_program_state->unblurred_outset_shadow.color = *color;
-    }
-  else
-    op->color.send = FALSE;
-
-  if (dx != current_program_state->unblurred_outset_shadow.dx ||
-      dy != current_program_state->unblurred_outset_shadow.dy)
-    {
-      op->offset.value[0] = dx;
-      op->offset.value[1] = dy;
-      op->offset.send = TRUE;
-
-      current_program_state->unblurred_outset_shadow.dx = dx;
-      current_program_state->unblurred_outset_shadow.dy = dy;
-    }
-  else
-    op->offset.send = FALSE;
-}
-
-void
-ops_set_linear_gradient (RenderOpBuilder     *self,
-                         guint                n_color_stops,
-                         const GskColorStop  *color_stops,
-                         gboolean             repeat,
-                         float                start_x,
-                         float                start_y,
-                         float                end_x,
-                         float                end_y)
-{
-  ProgramState *current_program_state = get_current_program_state (self);
-  OpLinearGradient *op;
-  const guint real_n_color_stops = MIN (GL_MAX_GRADIENT_STOPS, n_color_stops);
-
-  g_assert (current_program_state);
-
-  op = ops_begin (self, OP_CHANGE_LINEAR_GRADIENT);
-
-  /* We always save the n_color_stops value in the op so the renderer can use it in
-   * cases where we send the color stops, but not n_color_stops */
-  op->n_color_stops.value = real_n_color_stops;
-  if (current_program_state->linear_gradient.n_color_stops != real_n_color_stops)
-    {
-      op->n_color_stops.send = TRUE;
-      current_program_state->linear_gradient.n_color_stops = real_n_color_stops;
-    }
-  else
-    op->n_color_stops.send = FALSE;
-
-  op->color_stops.send = FALSE;
-  if (!op->n_color_stops.send)
-    {
-      g_assert (current_program_state->linear_gradient.n_color_stops == real_n_color_stops);
-
-      for (guint i = 0; i < real_n_color_stops; i ++)
-        {
-          const GskColorStop *s1 = &color_stops[i];
-          const GskColorStop *s2 = &current_program_state->linear_gradient.color_stops[i];
-
-          if (s1->offset != s2->offset ||
-              !gdk_rgba_equal (&s1->color, &s2->color))
-            {
-              op->color_stops.send = TRUE;
-              break;
-            }
-        }
-    }
-  else
-    op->color_stops.send = TRUE;
-
-  if (op->color_stops.send)
-    {
-      op->color_stops.value = color_stops;
-      memcpy (&current_program_state->linear_gradient.color_stops,
-              color_stops,
-              sizeof (GskColorStop) * real_n_color_stops);
-    }
-
-  op->repeat = repeat;
-  op->start_point[0] = start_x;
-  op->start_point[1] = start_y;
-  op->end_point[0] = end_x;
-  op->end_point[1] = end_y;
-}
-
-void
-ops_set_radial_gradient (RenderOpBuilder    *self,
-                         guint               n_color_stops,
-                         const GskColorStop *color_stops,
-                         gboolean            repeat,
-                         float               center_x,
-                         float               center_y,
-                         float               start,
-                         float               end,
-                         float               hradius,
-                         float               vradius)
-{
-  const guint real_n_color_stops = MIN (GL_MAX_GRADIENT_STOPS, n_color_stops);
-  OpRadialGradient *op;
-
-  /* TODO: State tracking? */
-
-  op = ops_begin (self, OP_CHANGE_RADIAL_GRADIENT);
-  op->n_color_stops.value = real_n_color_stops;
-  op->n_color_stops.send = true;
-  op->color_stops.value = color_stops;
-  op->color_stops.send = true;
-  op->center[0] = center_x;
-  op->center[1] = center_y;
-  op->radius[0] = hradius;
-  op->radius[1] = vradius;
-  op->start = start;
-  op->end = end;
-  op->repeat = repeat;
-}
-
-void
-ops_set_conic_gradient (RenderOpBuilder    *self,
-                        guint               n_color_stops,
-                        const GskColorStop *color_stops,
-                        float               center_x,
-                        float               center_y,
-                        float               angle)
-{
-  const guint real_n_color_stops = MIN (GL_MAX_GRADIENT_STOPS, n_color_stops);
-  OpConicGradient *op;
-
-  /* TODO: State tracking? */
-
-  op = ops_begin (self, OP_CHANGE_CONIC_GRADIENT);
-  op->n_color_stops.value = real_n_color_stops;
-  op->n_color_stops.send = true;
-  op->color_stops.value = color_stops;
-  op->color_stops.send = true;
-  op->center[0] = center_x;
-  op->center[1] = center_y;
-  op->angle = angle;
-}
-
diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h
deleted file mode 100644 (file)
index 551a1af..0000000
+++ /dev/null
@@ -1,353 +0,0 @@
-#ifndef __GSK_GL_RENDER_OPS_H__
-#define __GSK_GL_RENDER_OPS_H__
-
-#include <glib.h>
-#include <graphene.h>
-#include <gdk/gdk.h>
-
-#include "gskgldriverprivate.h"
-#include "gskroundedrectprivate.h"
-#include "gskglrenderer.h"
-#include "gskrendernodeprivate.h"
-
-#include "opbuffer.h"
-
-#define GL_N_VERTICES 6
-#define GL_N_PROGRAMS 15
-#define GL_MAX_GRADIENT_STOPS 6
-
-typedef struct
-{
-  float scale_x;
-  float scale_y;
-
-  float dx_before;
-  float dy_before;
-} OpsMatrixMetadata;
-
-typedef struct
-{
-  GskTransform *transform;
-  OpsMatrixMetadata metadata;
-} MatrixStackEntry;
-
-typedef struct
-{
-  GskTransform *modelview;
-  GskRoundedRect clip;
-  graphene_matrix_t projection;
-  int source_texture;
-  graphene_rect_t viewport;
-  float opacity;
-  /* Per-program state */
-  union {
-    GdkRGBA color;
-    struct {
-      graphene_matrix_t matrix;
-      graphene_vec4_t offset;
-    } color_matrix;
-    struct {
-      float widths[4];
-      GdkRGBA color;
-      GskRoundedRect outline;
-    } border;
-    struct {
-      GskRoundedRect outline;
-      float dx;
-      float dy;
-      float spread;
-      GdkRGBA color;
-    } inset_shadow;
-    struct {
-      GskRoundedRect outline;
-      float dx;
-      float dy;
-      float spread;
-      GdkRGBA color;
-    } unblurred_outset_shadow;
-    struct {
-      int n_color_stops;
-      GskColorStop color_stops[GL_MAX_GRADIENT_STOPS];
-      float start_point[2];
-      float end_point[2];
-    } linear_gradient;
-    struct {
-      int n_color_stops;
-      GskColorStop color_stops[GL_MAX_GRADIENT_STOPS];
-      float center[2];
-      float start;
-      float end;
-      float radius[2]; /* h/v */
-    } radial_gradient;
-    struct {
-      float width;
-      float height;
-      int uniform_data_len;
-      guchar uniform_data[32];
-    } gl_shader;
-  };
-} ProgramState;
-
-struct _Program
-{
-  const char *name;
-
-  int index;        /* Into the renderer's program array -1 for custom */
-
-  int id;
-  /* Common locations (gl_common)*/
-  int source_location;
-  int position_location;
-  int uv_location;
-  int alpha_location;
-  int viewport_location;
-  int projection_location;
-  int modelview_location;
-  int clip_rect_location;
-  union {
-    struct {
-      int color_location;
-    } color;
-    struct {
-      int color_location;
-    } coloring;
-    struct {
-      int color_matrix_location;
-      int color_offset_location;
-    } color_matrix;
-    struct {
-      int num_color_stops_location;
-      int color_stops_location;
-      int points_location;
-      int repeat_location;
-    } linear_gradient;
-    struct {
-      int num_color_stops_location;
-      int color_stops_location;
-      int geometry_location;
-      int range_location;
-      int repeat_location;
-    } radial_gradient;
-    struct {
-      int num_color_stops_location;
-      int color_stops_location;
-      int geometry_location;
-    } conic_gradient;
-    struct {
-      int blur_radius_location;
-      int blur_size_location;
-      int blur_dir_location;
-    } blur;
-    struct {
-      int color_location;
-      int spread_location;
-      int offset_location;
-      int outline_rect_location;
-    } inset_shadow;
-    struct {
-      int color_location;
-      int outline_rect_location;
-    } outset_shadow;
-    struct {
-      int outline_rect_location;
-      int color_location;
-      int spread_location;
-      int offset_location;
-    } unblurred_outset_shadow;
-    struct {
-      int color_location;
-      int widths_location;
-      int outline_rect_location;
-    } border;
-    struct {
-      int source2_location;
-      int progress_location;
-    } cross_fade;
-    struct {
-      int source2_location;
-      int mode_location;
-    } blend;
-    struct {
-      int child_bounds_location;
-      int texture_rect_location;
-    } repeat;
-    struct {
-      int size_location;
-      int args_locations[8];
-      int texture_locations[4];
-      GError *compile_error;
-    } glshader;
-  };
-  ProgramState state;
-};
-
-typedef struct {
-  int ref_count;
-  union {
-    Program programs[GL_N_PROGRAMS];
-    struct {
-      Program blend_program;
-      Program blit_program;
-      Program blur_program;
-      Program border_program;
-      Program color_matrix_program;
-      Program color_program;
-      Program coloring_program;
-      Program cross_fade_program;
-      Program inset_shadow_program;
-      Program linear_gradient_program;
-      Program radial_gradient_program;
-      Program conic_gradient_program;
-      Program outset_shadow_program;
-      Program repeat_program;
-      Program unblurred_outset_shadow_program;
-    };
-  };
-  GHashTable *custom_programs; /* GskGLShader -> Program* */
-} GskGLRendererPrograms;
-
-typedef struct
-{
-  GskGLRendererPrograms *programs;
-  Program *current_program;
-  int current_render_target;
-  int current_texture;
-
-  graphene_matrix_t current_projection;
-  graphene_rect_t current_viewport;
-  float current_opacity;
-  float dx, dy;
-  float scale_x, scale_y;
-
-  OpBuffer render_ops;
-  GArray *vertices;
-
-  GskGLRenderer *renderer;
-
-  /* Stack of modelview matrices */
-  GArray *mv_stack;
-  GskTransform *current_modelview;
-
-  /* Same thing */
-  GArray *clip_stack;
-  /* Pointer into clip_stack */
-  const GskRoundedRect *current_clip;
-  bool clip_is_rectilinear;
-} RenderOpBuilder;
-
-
-void              ops_dump_framebuffer   (RenderOpBuilder         *builder,
-                                          const char              *filename,
-                                          int                      width,
-                                          int                      height);
-void              ops_init               (RenderOpBuilder         *builder);
-void              ops_free               (RenderOpBuilder         *builder);
-void              ops_reset              (RenderOpBuilder         *builder);
-void              ops_push_debug_group    (RenderOpBuilder         *builder,
-                                           const char              *text);
-void              ops_pop_debug_group     (RenderOpBuilder         *builder);
-
-void              ops_finish             (RenderOpBuilder         *builder);
-void              ops_push_modelview     (RenderOpBuilder         *builder,
-                                          GskTransform            *transform);
-void              ops_set_modelview      (RenderOpBuilder         *builder,
-                                          GskTransform            *transform);
-void              ops_pop_modelview      (RenderOpBuilder         *builder);
-void              ops_set_program        (RenderOpBuilder         *builder,
-                                          Program                 *program);
-
-void              ops_push_clip          (RenderOpBuilder         *builder,
-                                          const GskRoundedRect    *clip);
-void              ops_pop_clip           (RenderOpBuilder         *builder);
-gboolean          ops_has_clip           (RenderOpBuilder         *builder);
-
-void              ops_transform_bounds_modelview (const RenderOpBuilder *builder,
-                                                  const graphene_rect_t *src,
-                                                  graphene_rect_t       *dst);
-
-graphene_matrix_t ops_set_projection     (RenderOpBuilder         *builder,
-                                          const graphene_matrix_t *projection);
-
-graphene_rect_t   ops_set_viewport       (RenderOpBuilder         *builder,
-                                          const graphene_rect_t   *viewport);
-
-void              ops_set_texture        (RenderOpBuilder         *builder,
-                                          int                      texture_id);
-void              ops_set_extra_texture  (RenderOpBuilder         *builder,
-                                          int                      texture_id,
-                                          int                      idx);
-
-int               ops_set_render_target  (RenderOpBuilder         *builder,
-                                          int                      render_target_id);
-
-float             ops_set_opacity        (RenderOpBuilder         *builder,
-                                          float                    opacity);
-void              ops_set_color          (RenderOpBuilder         *builder,
-                                          const GdkRGBA           *color);
-
-void              ops_set_color_matrix   (RenderOpBuilder         *builder,
-                                          const graphene_matrix_t *matrix,
-                                          const graphene_vec4_t   *offset);
-
-void              ops_set_border         (RenderOpBuilder         *builder,
-                                          const GskRoundedRect    *outline);
-void              ops_set_border_width   (RenderOpBuilder         *builder,
-                                          const float             *widths);
-
-void              ops_set_border_color   (RenderOpBuilder         *builder,
-                                          const GdkRGBA           *color);
-void              ops_set_inset_shadow   (RenderOpBuilder         *self,
-                                          const GskRoundedRect     outline,
-                                          float                    spread,
-                                          const GdkRGBA           *color,
-                                          float                    dx,
-                                          float                    dy);
-void              ops_set_gl_shader_args (RenderOpBuilder         *builder,
-                                          GskGLShader             *shader,
-                                          float                    width,
-                                          float                    height,
-                                          const guchar            *uniform_data);
-void              ops_set_unblurred_outset_shadow   (RenderOpBuilder         *self,
-                                                     const GskRoundedRect     outline,
-                                                     float                    spread,
-                                                     const GdkRGBA           *color,
-                                                     float                    dx,
-                                                     float                    dy);
-
-void              ops_set_linear_gradient (RenderOpBuilder     *self,
-                                           guint                n_color_stops,
-                                           const GskColorStop  *color_stops,
-                                           gboolean             repeat,
-                                           float                start_x,
-                                           float                start_y,
-                                           float                end_x,
-                                           float                end_y);
-void              ops_set_radial_gradient (RenderOpBuilder        *self,
-                                           guint                   n_color_stops,
-                                           const GskColorStop     *color_stops,
-                                           gboolean                repeat,
-                                           float                   center_x,
-                                           float                   center_y,
-                                           float                   start,
-                                           float                   end,
-                                           float                   hradius,
-                                           float                   vradius);
-void              ops_set_conic_gradient  (RenderOpBuilder        *self,
-                                           guint                   n_color_stops,
-                                           const GskColorStop     *color_stops,
-                                           float                   center_x,
-                                           float                   center_y,
-                                           float                   angle);
-
-GskQuadVertex *   ops_draw               (RenderOpBuilder        *builder,
-                                          const GskQuadVertex     vertex_data[GL_N_VERTICES]);
-
-void              ops_offset             (RenderOpBuilder        *builder,
-                                          float                   x,
-                                          float                   y);
-
-gpointer          ops_begin              (RenderOpBuilder        *builder,
-                                          OpKind                  kind);
-OpBuffer         *ops_get_buffer         (RenderOpBuilder        *builder);
-
-#endif
diff --git a/gsk/gl/gskglshaderbuilder.c b/gsk/gl/gskglshaderbuilder.c
deleted file mode 100644 (file)
index d16ad4f..0000000
+++ /dev/null
@@ -1,271 +0,0 @@
-#include "config.h"
-
-#include "gskglshaderbuilderprivate.h"
-
-#include "gskdebugprivate.h"
-
-#include <gdk/gdk.h>
-#include <epoxy/gl.h>
-
-void
-gsk_gl_shader_builder_init (GskGLShaderBuilder *self,
-                            const char         *common_preamble_resource_path,
-                            const char         *vs_preamble_resource_path,
-                            const char         *fs_preamble_resource_path)
-{
-  memset (self, 0, sizeof (*self));
-
-  self->preamble = g_resources_lookup_data (common_preamble_resource_path, 0, NULL);
-  self->vs_preamble = g_resources_lookup_data (vs_preamble_resource_path, 0, NULL);
-  self->fs_preamble = g_resources_lookup_data (fs_preamble_resource_path, 0, NULL);
-
-  g_assert (self->preamble);
-  g_assert (self->vs_preamble);
-  g_assert (self->fs_preamble);
-}
-
-void
-gsk_gl_shader_builder_finish (GskGLShaderBuilder *self)
-{
-  g_bytes_unref (self->preamble);
-  g_bytes_unref (self->vs_preamble);
-  g_bytes_unref (self->fs_preamble);
-}
-
-void
-gsk_gl_shader_builder_set_glsl_version (GskGLShaderBuilder *self,
-                                        int                 version)
-{
-  self->version = version;
-}
-
-static void
-prepend_line_numbers (char    *code,
-                      GString *s)
-{
-  char *p;
-  int line;
-
-  p = code;
-  line = 1;
-  while (*p)
-    {
-      char *end = strchr (p, '\n');
-      if (end)
-        end = end + 1; /* Include newline */
-      else
-        end = p + strlen (p);
-
-      g_string_append_printf (s, "%3d| ", line++);
-      g_string_append_len (s, p, end - p);
-
-      p = end;
-    }
-}
-
-static gboolean
-check_shader_error (int          shader_id,
-                    int          shader_type,
-                    const char  *resource_path,
-                    GError     **error)
-{
-  int status;
-  int log_len;
-  char *buffer;
-  int code_len;
-  char *code;
-  GString *s;
-
-  glGetShaderiv (shader_id, GL_COMPILE_STATUS, &status);
-
-  if (G_LIKELY (status == GL_TRUE))
-    return TRUE;
-
-  glGetShaderiv (shader_id, GL_INFO_LOG_LENGTH, &log_len);
-  buffer = g_malloc0 (log_len + 1);
-  glGetShaderInfoLog (shader_id, log_len, NULL, buffer);
-
-  glGetShaderiv (shader_id, GL_SHADER_SOURCE_LENGTH, &code_len);
-  code = g_malloc0 (code_len + 1);
-  glGetShaderSource (shader_id, code_len, NULL, code);
-
-  s = g_string_new ("");
-  prepend_line_numbers (code, s);
-
-  g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_COMPILATION_FAILED,
-               "Compilation failure in %s shader %s.\nSource Code:\n%s\n\nError Message:\n%s\n\n",
-               (shader_type == GL_FRAGMENT_SHADER ? "fragment" : "vertex"),
-               resource_path,
-               s->str,
-               buffer);
-
-  g_string_free (s, TRUE);
-  g_free (buffer);
-  g_free (code);
-
-  return FALSE;
-}
-
-static void
-print_shader_info (const char *prefix,
-                   int         shader_id,
-                   const char *resource_path)
-{
-  if (GSK_DEBUG_CHECK(SHADERS))
-    {
-      int code_len;
-      char *code;
-      GString *s;
-
-      glGetShaderiv (shader_id, GL_SHADER_SOURCE_LENGTH, &code_len);
-      code = g_malloc0 (code_len + 1);
-      glGetShaderSource (shader_id, code_len, NULL, code);
-
-      s = g_string_new ("");
-      prepend_line_numbers (code, s);
-
-      g_message ("%s %d, %s:\n%s", prefix, shader_id, resource_path, s->str);
-      g_string_free (s,  TRUE);
-      g_free (code);
-    }
-}
-
-int
-gsk_gl_shader_builder_create_program (GskGLShaderBuilder  *self,
-                                      const char          *resource_path,
-                                      const char          *extra_fragment_snippet,
-                                      gsize                extra_fragment_length,
-                                      GError             **error)
-{
-
-  GBytes *source_bytes = g_resources_lookup_data (resource_path, 0, NULL);
-  char version_buffer[64];
-  const char *source;
-  const char *vertex_shader_start;
-  const char *fragment_shader_start;
-  int vertex_id;
-  int fragment_id;
-  int program_id = -1;
-  int status;
-
-  g_assert (source_bytes);
-
-  source = g_bytes_get_data (source_bytes, NULL);
-  vertex_shader_start = strstr (source, "VERTEX_SHADER");
-  fragment_shader_start = strstr (source, "FRAGMENT_SHADER");
-
-  g_assert (vertex_shader_start);
-  g_assert (fragment_shader_start);
-
-  /* They both start at the next newline */
-  vertex_shader_start = strstr (vertex_shader_start, "\n");
-  fragment_shader_start = strstr (fragment_shader_start, "\n");
-
-  g_snprintf (version_buffer, sizeof (version_buffer),
-              "#version %d\n", self->version);
-
-  vertex_id = glCreateShader (GL_VERTEX_SHADER);
-  glShaderSource (vertex_id, 8,
-                  (const char *[]) {
-                    version_buffer,
-                    self->debugging ? "#define GSK_DEBUG 1\n" : "",
-                    self->legacy ? "#define GSK_LEGACY 1\n" : "",
-                    self->gl3 ? "#define GSK_GL3 1\n" : "",
-                    self->gles ? "#define GSK_GLES 1\n" : "",
-                    g_bytes_get_data (self->preamble, NULL),
-                    g_bytes_get_data (self->vs_preamble, NULL),
-                    vertex_shader_start
-                  },
-                  (int[]) {
-                    -1,
-                    -1,
-                    -1,
-                    -1,
-                    -1,
-                    -1,
-                    -1,
-                    fragment_shader_start - vertex_shader_start
-                  });
-  glCompileShader (vertex_id);
-
-  if (!check_shader_error (vertex_id, GL_VERTEX_SHADER, resource_path, error))
-    {
-      glDeleteShader (vertex_id);
-      goto out;
-    }
-
-  print_shader_info ("Vertex shader", vertex_id, resource_path);
-
-  fragment_id = glCreateShader (GL_FRAGMENT_SHADER);
-  glShaderSource (fragment_id, 9,
-                  (const char *[]) {
-                    version_buffer,
-                    self->debugging ? "#define GSK_DEBUG 1\n" : "",
-                    self->legacy ? "#define GSK_LEGACY 1\n" : "",
-                    self->gl3 ? "#define GSK_GL3 1\n" : "",
-                    self->gles ? "#define GSK_GLES 1\n" : "",
-                    g_bytes_get_data (self->preamble, NULL),
-                    g_bytes_get_data (self->fs_preamble, NULL),
-                    fragment_shader_start,
-                    extra_fragment_snippet ? extra_fragment_snippet : ""
-                  },
-                  (int[]) {
-                    -1,
-                    -1,
-                    -1,
-                    -1,
-                    -1,
-                    -1,
-                    -1,
-                    -1,
-                    extra_fragment_length,
-                  });
-  glCompileShader (fragment_id);
-
-  if (!check_shader_error (fragment_id, GL_FRAGMENT_SHADER, resource_path, error))
-    {
-      glDeleteShader (fragment_id);
-      goto out;
-    }
-
-  print_shader_info ("Fragment shader", fragment_id, resource_path);
-
-  program_id = glCreateProgram ();
-  glAttachShader (program_id, vertex_id);
-  glAttachShader (program_id, fragment_id);
-  glBindAttribLocation (program_id, 0, "aPosition");
-  glBindAttribLocation (program_id, 1, "aUv");
-  glLinkProgram (program_id);
-  glDetachShader (program_id, vertex_id);
-  glDetachShader (program_id, fragment_id);
-
-  glGetProgramiv (program_id, GL_LINK_STATUS, &status);
-  if (status == GL_FALSE)
-    {
-      char *buffer = NULL;
-      int log_len = 0;
-
-      glGetProgramiv (program_id, GL_INFO_LOG_LENGTH, &log_len);
-
-      buffer = g_malloc0 (log_len + 1);
-      glGetProgramInfoLog (program_id, log_len, NULL, buffer);
-
-      g_warning ("Linking failure in shader:\n%s", buffer);
-      g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_LINK_FAILED,
-                   "Linking failure in shader: %s", buffer);
-
-      g_free (buffer);
-
-      glDeleteProgram (program_id);
-      program_id = -1;
-    }
-
-  glDeleteShader (vertex_id);
-  glDeleteShader (fragment_id);
-
-out:
-  g_bytes_unref (source_bytes);
-
-  return program_id;
-}
-
diff --git a/gsk/gl/gskglshaderbuilderprivate.h b/gsk/gl/gskglshaderbuilderprivate.h
deleted file mode 100644 (file)
index 870df05..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef __GSK_SHADER_BUILDER_PRIVATE_H__
-#define __GSK_SHADER_BUILDER_PRIVATE_H__
-
-#include <gdk/gdk.h>
-#include <graphene.h>
-
-G_BEGIN_DECLS
-
-typedef struct
-{
-  GBytes *preamble;
-  GBytes *vs_preamble;
-  GBytes *fs_preamble;
-
-  int version;
-
-  guint debugging: 1;
-  guint gles: 1;
-  guint gl3: 1;
-  guint legacy: 1;
-
-} GskGLShaderBuilder;
-
-
-void   gsk_gl_shader_builder_init             (GskGLShaderBuilder  *self,
-                                               const char          *common_preamble_resource_path,
-                                               const char          *vs_preamble_resource_path,
-                                               const char          *fs_preamble_resource_path);
-void   gsk_gl_shader_builder_finish           (GskGLShaderBuilder  *self);
-
-void   gsk_gl_shader_builder_set_glsl_version (GskGLShaderBuilder  *self,
-                                               int                  version);
-
-int    gsk_gl_shader_builder_create_program   (GskGLShaderBuilder  *self,
-                                               const char          *resource_path,
-                                               const char          *extra_fragment_snippet,
-                                               gsize                extra_fragment_length,
-                                               GError             **error);
-
-G_END_DECLS
-
-#endif /* __GSK_SHADER_BUILDER_PRIVATE_H__ */
diff --git a/gsk/gl/gskglshadowcache.c b/gsk/gl/gskglshadowcache.c
deleted file mode 100644 (file)
index a0eeef9..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-
-#include "gskglshadowcacheprivate.h"
-
-#define MAX_UNUSED_FRAMES (16 * 5)
-
-typedef struct
-{
-  GskRoundedRect outline;
-  float blur_radius;
-} CacheKey;
-
-typedef struct
-{
-  GskRoundedRect outline;
-  float blur_radius;
-
-  int texture_id;
-  int unused_frames;
-} CacheItem;
-
-static gboolean
-key_equal (const void *x,
-           const void *y)
-{
-  const CacheKey *a = x;
-  const CacheKey *b = y;
-
-  return a->blur_radius == b->blur_radius &&
-         graphene_size_equal (&a->outline.corner[0], &b->outline.corner[0]) &&
-         graphene_size_equal (&a->outline.corner[1], &b->outline.corner[1]) &&
-         graphene_size_equal (&a->outline.corner[2], &b->outline.corner[2]) &&
-         graphene_size_equal (&a->outline.corner[3], &b->outline.corner[3]) &&
-         graphene_rect_equal (&a->outline.bounds, &b->outline.bounds);
-}
-
-void
-gsk_gl_shadow_cache_init (GskGLShadowCache *self)
-{
-  self->textures = g_array_new (FALSE, TRUE, sizeof (CacheItem));
-}
-
-void
-gsk_gl_shadow_cache_free (GskGLShadowCache *self,
-                          GskGLDriver      *gl_driver)
-{
-  guint i, p;
-
-  for (i = 0, p = self->textures->len; i < p; i ++)
-    {
-      const CacheItem *item = &g_array_index (self->textures, CacheItem, i);
-
-      gsk_gl_driver_destroy_texture (gl_driver, item->texture_id);
-    }
-
-  g_array_free (self->textures, TRUE);
-  self->textures = NULL;
-}
-
-void
-gsk_gl_shadow_cache_begin_frame (GskGLShadowCache *self,
-                                 GskGLDriver      *gl_driver)
-{
-  guint i, p;
-
-  for (i = 0, p = self->textures->len; i < p; i ++)
-    {
-      CacheItem *item = &g_array_index (self->textures, CacheItem, i);
-
-      if (item->unused_frames > MAX_UNUSED_FRAMES)
-        {
-          gsk_gl_driver_destroy_texture (gl_driver, item->texture_id);
-          g_array_remove_index_fast (self->textures, i);
-          p --;
-          i --;
-        }
-      else
-        {
-          item->unused_frames ++;
-        }
-    }
-}
-
-/* XXX
- * The offset origin should always be at 0/0, or the blur radius should just go
- * away since it defines the origin position anyway?
- */
-int
-gsk_gl_shadow_cache_get_texture_id (GskGLShadowCache     *self,
-                                    GskGLDriver          *gl_driver,
-                                    const GskRoundedRect *shadow_rect,
-                                    float                 blur_radius)
-{
-  CacheItem *item= NULL;
-  guint i;
-
-  g_assert (self != NULL);
-  g_assert (gl_driver != NULL);
-  g_assert (shadow_rect != NULL);
-
-  for (i = 0; i < self->textures->len; i ++)
-    {
-      CacheItem *k = &g_array_index (self->textures, CacheItem, i);
-
-      if (key_equal (&(CacheKey){*shadow_rect, blur_radius},
-                     &(CacheKey){k->outline, k->blur_radius}))
-        {
-          item = k;
-          break;
-        }
-    }
-
-  if (item == NULL)
-    return 0;
-
-  item->unused_frames = 0;
-
-  g_assert (item->texture_id != 0);
-
-  return item->texture_id;
-}
-
-void
-gsk_gl_shadow_cache_commit (GskGLShadowCache     *self,
-                            const GskRoundedRect *shadow_rect,
-                            float                 blur_radius,
-                            int                   texture_id)
-{
-  CacheItem *item;
-
-  g_assert (self != NULL);
-  g_assert (shadow_rect != NULL);
-  g_assert (texture_id > 0);
-
-  g_array_set_size (self->textures, self->textures->len + 1);
-  item = &g_array_index (self->textures, CacheItem, self->textures->len - 1);
-
-  item->outline = *shadow_rect;
-  item->blur_radius = blur_radius;
-  item->unused_frames = 0;
-  item->texture_id = texture_id;
-}
diff --git a/gsk/gl/gskglshadowcacheprivate.h b/gsk/gl/gskglshadowcacheprivate.h
deleted file mode 100644 (file)
index 6623f16..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-#ifndef __GSK_GL_SHADOW_CACHE_H__
-#define __GSK_GL_SHADOW_CACHE_H__
-
-#include <glib.h>
-#include "gskgldriverprivate.h"
-#include "gskroundedrect.h"
-
-typedef struct
-{
-  GArray *textures;
-} GskGLShadowCache;
-
-
-void gsk_gl_shadow_cache_init           (GskGLShadowCache     *self);
-void gsk_gl_shadow_cache_free           (GskGLShadowCache     *self,
-                                         GskGLDriver          *gl_driver);
-void gsk_gl_shadow_cache_begin_frame    (GskGLShadowCache     *self,
-                                         GskGLDriver          *gl_driver);
-int  gsk_gl_shadow_cache_get_texture_id (GskGLShadowCache     *self,
-                                         GskGLDriver          *gl_driver,
-                                         const GskRoundedRect *shadow_rect,
-                                         float                 blur_radius);
-void gsk_gl_shadow_cache_commit         (GskGLShadowCache     *self,
-                                         const GskRoundedRect *shadow_rect,
-                                         float                 blur_radius,
-                                         int                   texture_id);
-
-
-#endif
diff --git a/gsk/gl/gskgltextureatlas.c b/gsk/gl/gskgltextureatlas.c
deleted file mode 100644 (file)
index 9db2d8e..0000000
+++ /dev/null
@@ -1,309 +0,0 @@
-
-#include "config.h"
-#include "gskgltextureatlasprivate.h"
-#include "gskdebugprivate.h"
-#include "gdkglcontextprivate.h"
-#include <epoxy/gl.h>
-
-#define ATLAS_SIZE (512)
-#define MAX_OLD_RATIO 0.5
-
-static void
-free_atlas (gpointer v)
-{
-  GskGLTextureAtlas *atlas = v;
-
-  gsk_gl_texture_atlas_free (atlas);
-
-  g_free (atlas);
-}
-
-GskGLTextureAtlases *
-gsk_gl_texture_atlases_new (void)
-{
-  GskGLTextureAtlases *self;
-
-  self = g_new (GskGLTextureAtlases, 1);
-  self->atlases = g_ptr_array_new_with_free_func (free_atlas);
-
-  self->ref_count = 1;
-
-  return self;
-}
-
-GskGLTextureAtlases *
-gsk_gl_texture_atlases_ref (GskGLTextureAtlases *self)
-{
-  self->ref_count++;
-
-  return self;
-}
-
-void
-gsk_gl_texture_atlases_unref (GskGLTextureAtlases *self)
-{
-  g_assert (self->ref_count > 0);
-
-  if (self->ref_count == 1)
-    {
-      g_ptr_array_unref (self->atlases);
-      g_free (self);
-      return;
-    }
-
-  self->ref_count--;
-}
-
-#if 0
-static void
-write_atlas_to_png (GskGLTextureAtlas *atlas,
-                    const char        *filename)
-{
-  int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, atlas->width);
-  guchar *data = g_malloc (atlas->height * stride);
-  cairo_surface_t *s;
-
-  glBindTexture (GL_TEXTURE_2D, atlas->texture_id);
-  glGetTexImage (GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data);
-  s = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, atlas->width, atlas->height, stride);
-  cairo_surface_write_to_png (s, filename);
-
-  cairo_surface_destroy (s);
-  g_free (data);
-}
-#endif
-
-void
-gsk_gl_texture_atlases_begin_frame (GskGLTextureAtlases *self,
-                                    GPtrArray           *removed)
-{
-  int i;
-
-  for (i = self->atlases->len - 1; i >= 0; i--)
-    {
-      GskGLTextureAtlas *atlas = g_ptr_array_index (self->atlases, i);
-
-      if (gsk_gl_texture_atlas_get_unused_ratio (atlas) > MAX_OLD_RATIO)
-        {
-          GSK_NOTE(GLYPH_CACHE,
-                   g_message ("Dropping atlas %d (%g.2%% old)", i,
-                              100.0 * gsk_gl_texture_atlas_get_unused_ratio (atlas)));
-
-          if (atlas->texture_id != 0)
-            {
-              glDeleteTextures (1, &atlas->texture_id);
-              atlas->texture_id = 0;
-            }
-
-          g_ptr_array_add (removed, atlas);
-          g_ptr_array_remove_index (self->atlases, i);
-       }
-    }
-
-  GSK_NOTE(GLYPH_CACHE, {
-    static guint timestamp;
-    if (timestamp++ % 60 == 0)
-      g_message ("%d atlases", self->atlases->len);
-  });
-
-
-#if 0
-  {
-    static guint timestamp;
-
-    timestamp++;
-    if (timestamp % 10 == 0)
-      for (i = 0; i < self->atlases->len; i++)
-        {
-          GskGLTextureAtlas *atlas = g_ptr_array_index (self->atlases, i);
-
-          if (atlas->texture_id)
-            {
-              char *filename;
-
-              filename = g_strdup_printf ("textureatlas%d-%u.png", i, timestamp);
-              write_atlas_to_png (atlas, filename);
-              g_free (filename);
-            }
-         }
-   }
-#endif
-}
-
-gboolean
-gsk_gl_texture_atlases_pack (GskGLTextureAtlases *self,
-                             int                  width,
-                             int                  height,
-                             GskGLTextureAtlas  **atlas_out,
-                             int                 *out_x,
-                             int                 *out_y)
-{
-  GskGLTextureAtlas *atlas;
-  int x, y;
-  int i;
-
-  g_assert (width  < ATLAS_SIZE);
-  g_assert (height < ATLAS_SIZE);
-
-  atlas = NULL;
-
-  for (i = 0; i < self->atlases->len; i++)
-    {
-      atlas = g_ptr_array_index (self->atlases, i);
-
-      if (gsk_gl_texture_atlas_pack (atlas, width, height, &x, &y))
-        break;
-
-      atlas = NULL;
-    }
-
-  if (atlas == NULL)
-    {
-      /* No atlas has enough space, so create a new one... */
-      atlas = g_malloc (sizeof (GskGLTextureAtlas));
-      gsk_gl_texture_atlas_init (atlas, ATLAS_SIZE, ATLAS_SIZE);
-      gsk_gl_texture_atlas_realize (atlas);
-      g_ptr_array_add (self->atlases, atlas);
-
-      /* Pack it onto that one, which surely has enough space... */
-      if (!gsk_gl_texture_atlas_pack (atlas, width, height, &x, &y))
-        g_assert_not_reached ();
-
-      GSK_NOTE(GLYPH_CACHE, g_message ("adding new atlas"));
-    }
-
-  *atlas_out = atlas;
-  *out_x = x;
-  *out_y = y;
-
-  return TRUE;
-}
-
-void
-gsk_gl_texture_atlas_init (GskGLTextureAtlas *self,
-                           int                width,
-                           int                height)
-{
-  memset (self, 0, sizeof (*self));
-
-  self->texture_id = 0;
-  self->width = width;
-  self->height = height;
-
-  /* TODO: We might want to change the strategy about the amount of
-   *       nodes here? stb_rect_pack.h says with is optimal. */
-  self->nodes = g_malloc0 (sizeof (struct stbrp_node) * width);
-  stbrp_init_target (&self->context,
-                     width, height,
-                     self->nodes,
-                     width);
-
-  gsk_gl_texture_atlas_realize (self);
-}
-
-void
-gsk_gl_texture_atlas_free (GskGLTextureAtlas *self)
-{
-  if (self->texture_id != 0)
-    {
-      glDeleteTextures (1, &self->texture_id);
-      self->texture_id = 0;
-    }
-
-  g_clear_pointer (&self->nodes, g_free);
-}
-
-void
-gsk_gl_texture_atlas_mark_unused (GskGLTextureAtlas *self,
-                                  int                width,
-                                  int                height)
-{
-  self->unused_pixels += (width * height);
-}
-
-
-void
-gsk_gl_texture_atlas_mark_used (GskGLTextureAtlas *self,
-                                int                width,
-                                int                height)
-{
-  self->unused_pixels -= (width * height);
-
-  g_assert (self->unused_pixels >= 0);
-}
-
-gboolean
-gsk_gl_texture_atlas_pack (GskGLTextureAtlas *self,
-                           int                width,
-                           int                height,
-                           int               *out_x,
-                           int               *out_y)
-{
-  stbrp_rect rect;
-
-  g_assert (out_x);
-  g_assert (out_y);
-
-  rect.w = width;
-  rect.h = height;
-
-  stbrp_pack_rects (&self->context, &rect, 1);
-
-  if (rect.was_packed)
-    {
-      *out_x = rect.x;
-      *out_y = rect.y;
-    }
-
-  return rect.was_packed;
-}
-
-double
-gsk_gl_texture_atlas_get_unused_ratio (const GskGLTextureAtlas *self)
-{
-  if (self->unused_pixels > 0)
-    return (double)(self->unused_pixels) / (double)(self->width * self->height);
-
-  return 0.0;
-}
-
-/* Not using gdk_gl_driver_create_texture here, since we want
- * this texture to survive the driver and stay around until
- * the display gets closed.
- */
-static guint
-create_shared_texture (int width,
-                       int height)
-{
-  guint texture_id;
-
-  glGenTextures (1, &texture_id);
-  glBindTexture (GL_TEXTURE_2D, texture_id);
-
-  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
-  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
-  if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ()))
-    glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-  else
-    glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
-
-  glBindTexture (GL_TEXTURE_2D, 0);
-
-  return texture_id;
-}
-
-void
-gsk_gl_texture_atlas_realize (GskGLTextureAtlas *atlas)
-{
-  if (atlas->texture_id)
-    return;
-
-  atlas->texture_id = create_shared_texture (atlas->width, atlas->height);
-  gdk_gl_context_label_object_printf (gdk_gl_context_get_current (),
-                                      GL_TEXTURE, atlas->texture_id,
-                                      "Texture atlas %d", atlas->texture_id);
-}
diff --git a/gsk/gl/gskgltextureatlasprivate.h b/gsk/gl/gskgltextureatlasprivate.h
deleted file mode 100644 (file)
index fc4f036..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-
-#ifndef __GSK_GL_TEXTURE_ATLAS_H__
-#define __GSK_GL_TEXTURE_ATLAS_H__
-
-#include "stb_rect_pack.h"
-#include "gskglimageprivate.h"
-#include "gskgldriverprivate.h"
-
-struct _GskGLTextureAtlas
-{
-  struct stbrp_context context;
-  struct stbrp_node *nodes;
-
-  int width;
-  int height;
-
-  guint texture_id;
-
-  int unused_pixels; /* Pixels of rects that have been used at some point,
-                        But are now unused. */
-
-  void *user_data;
-};
-typedef struct _GskGLTextureAtlas GskGLTextureAtlas;
-
-struct _GskGLTextureAtlases
-{
-  int ref_count;
-
-  GPtrArray *atlases;
-};
-typedef struct _GskGLTextureAtlases GskGLTextureAtlases;
-
-GskGLTextureAtlases *gsk_gl_texture_atlases_new         (void);
-GskGLTextureAtlases *gsk_gl_texture_atlases_ref         (GskGLTextureAtlases *atlases);
-void                 gsk_gl_texture_atlases_unref       (GskGLTextureAtlases *atlases);
-
-void                 gsk_gl_texture_atlases_begin_frame (GskGLTextureAtlases *atlases,
-                                                         GPtrArray           *removed);
-gboolean             gsk_gl_texture_atlases_pack        (GskGLTextureAtlases *atlases,
-                                                         int                  width,
-                                                         int                  height,
-                                                         GskGLTextureAtlas  **atlas_out,
-                                                         int                 *out_x,
-                                                         int                 *out_y);
-
-void        gsk_gl_texture_atlas_init              (GskGLTextureAtlas       *self,
-                                                    int                      width,
-                                                    int                      height);
-
-void        gsk_gl_texture_atlas_free              (GskGLTextureAtlas       *self);
-
-void        gsk_gl_texture_atlas_realize           (GskGLTextureAtlas       *self);
-
-void        gsk_gl_texture_atlas_mark_unused       (GskGLTextureAtlas       *self,
-                                                    int                      width,
-                                                    int                      height);
-
-void        gsk_gl_texture_atlas_mark_used         (GskGLTextureAtlas       *self,
-                                                    int                      width,
-                                                    int                      height);
-
-
-gboolean    gsk_gl_texture_atlas_pack              (GskGLTextureAtlas       *self,
-                                                    int                      width,
-                                                    int                      height,
-                                                    int                     *out_x,
-                                                    int                     *out_y);
-
-double      gsk_gl_texture_atlas_get_unused_ratio  (const GskGLTextureAtlas *self);
-
-#endif
diff --git a/gsk/gl/opbuffer.c b/gsk/gl/opbuffer.c
deleted file mode 100644 (file)
index 806b8f7..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-#include "opbuffer.h"
-
-#include <string.h>
-
-static guint op_sizes[OP_LAST] = {
-  0,
-  sizeof (OpOpacity),
-  sizeof (OpColor),
-  sizeof (OpMatrix),
-  sizeof (OpMatrix),
-  sizeof (OpProgram),
-  sizeof (OpRenderTarget),
-  sizeof (OpClip),
-  sizeof (OpViewport),
-  sizeof (OpTexture),
-  sizeof (OpRepeat),
-  sizeof (OpLinearGradient),
-  sizeof (OpRadialGradient),
-  sizeof (OpColorMatrix),
-  sizeof (OpBlur),
-  sizeof (OpShadow),
-  sizeof (OpOutsetShadow),
-  sizeof (OpBorder),
-  sizeof (OpBorder),
-  sizeof (OpBorder),
-  sizeof (OpCrossFade),
-  sizeof (OpShadow),
-  0,
-  sizeof (OpDraw),
-  sizeof (OpDumpFrameBuffer),
-  sizeof (OpDebugGroup),
-  0,
-  sizeof (OpBlend),
-  sizeof (OpGLShader),
-  sizeof (OpExtraTexture),
-  sizeof (OpConicGradient),
-};
-
-void
-op_buffer_init (OpBuffer *buffer)
-{
-  static gsize initialized = FALSE;
-
-  if (g_once_init_enter (&initialized))
-    {
-      guint i;
-
-      for (i = 0; i < G_N_ELEMENTS (op_sizes); i++)
-        {
-          guint size = op_sizes[i];
-
-          if (size > 0)
-            {
-              /* Round all op entry sizes to the nearest 16 to ensure
-               * that we guarantee proper alignments for all op entries.
-               * This is only done once on first use.
-               */
-#define CHECK_SIZE(s) else if (size < (s)) { size = s; }
-              if (0) {}
-              CHECK_SIZE (16)
-              CHECK_SIZE (32)
-              CHECK_SIZE (48)
-              CHECK_SIZE (64)
-              CHECK_SIZE (80)
-              CHECK_SIZE (96)
-              CHECK_SIZE (112)
-              CHECK_SIZE (128)
-              CHECK_SIZE (144)
-              CHECK_SIZE (160)
-              CHECK_SIZE (176)
-              CHECK_SIZE (192)
-              else g_assert_not_reached ();
-#undef CHECK_SIZE
-
-              op_sizes[i] = size;
-            }
-        }
-
-      g_once_init_leave (&initialized, TRUE);
-    }
-
-  memset (buffer, 0, sizeof *buffer);
-
-  buffer->buflen = 4096;
-  buffer->bufpos = 0;
-  buffer->buf = g_malloc (buffer->buflen);
-  buffer->index = g_array_new (FALSE, FALSE, sizeof (OpBufferEntry));
-
-  /* Add dummy entry to guarantee non-empty index */
-  op_buffer_add (buffer, OP_NONE);
-}
-
-void
-op_buffer_destroy (OpBuffer *buffer)
-{
-  g_free (buffer->buf);
-  g_array_unref (buffer->index);
-}
-
-void
-op_buffer_clear (OpBuffer *buffer)
-{
-  if (buffer->index->len > 1)
-    g_array_remove_range (buffer->index, 1, buffer->index->len - 1);
-  buffer->bufpos = 0;
-}
-
-static inline void
-ensure_buffer_space_for (OpBuffer *buffer,
-                         guint     size)
-{
-  if G_UNLIKELY (buffer->bufpos + size >= buffer->buflen)
-    {
-      buffer->buflen *= 2;
-      buffer->buf = g_realloc (buffer->buf, buffer->buflen);
-    }
-}
-
-gpointer
-op_buffer_add (OpBuffer *buffer,
-               OpKind    kind)
-{
-  guint size = op_sizes[kind];
-  OpBufferEntry entry;
-
-  entry.pos = buffer->bufpos;
-  entry.kind = kind;
-
-  if (size > 0)
-    ensure_buffer_space_for (buffer, size);
-
-  g_array_append_val (buffer->index, entry);
-
-  buffer->bufpos += size;
-
-  return &buffer->buf[entry.pos];
-}
diff --git a/gsk/gl/opbuffer.h b/gsk/gl/opbuffer.h
deleted file mode 100644 (file)
index ea95424..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-#ifndef __OP_BUFFER_H__
-#define __OP_BUFFER_H__
-
-#include <gdk/gdk.h>
-#include <gsk/gsk.h>
-#include <graphene.h>
-
-#include "gskgldriverprivate.h"
-
-typedef struct _Program Program;
-
-typedef enum
-{
-  OP_NONE                              =  0,
-  OP_CHANGE_OPACITY                    =  1,
-  OP_CHANGE_COLOR                      =  2,
-  OP_CHANGE_PROJECTION                 =  3,
-  OP_CHANGE_MODELVIEW                  =  4,
-  OP_CHANGE_PROGRAM                    =  5,
-  OP_CHANGE_RENDER_TARGET              =  6,
-  OP_CHANGE_CLIP                       =  7,
-  OP_CHANGE_VIEWPORT                   =  8,
-  OP_CHANGE_SOURCE_TEXTURE             =  9,
-  OP_CHANGE_REPEAT                     = 10,
-  OP_CHANGE_LINEAR_GRADIENT            = 11,
-  OP_CHANGE_RADIAL_GRADIENT            = 12,
-  OP_CHANGE_COLOR_MATRIX               = 13,
-  OP_CHANGE_BLUR                       = 14,
-  OP_CHANGE_INSET_SHADOW               = 15,
-  OP_CHANGE_OUTSET_SHADOW              = 16,
-  OP_CHANGE_BORDER                     = 17,
-  OP_CHANGE_BORDER_COLOR               = 18,
-  OP_CHANGE_BORDER_WIDTH               = 19,
-  OP_CHANGE_CROSS_FADE                 = 20,
-  OP_CHANGE_UNBLURRED_OUTSET_SHADOW    = 21,
-  OP_CLEAR                             = 22,
-  OP_DRAW                              = 23,
-  OP_DUMP_FRAMEBUFFER                  = 24,
-  OP_PUSH_DEBUG_GROUP                  = 25,
-  OP_POP_DEBUG_GROUP                   = 26,
-  OP_CHANGE_BLEND                      = 27,
-  OP_CHANGE_GL_SHADER_ARGS             = 28,
-  OP_CHANGE_EXTRA_SOURCE_TEXTURE       = 29,
-  OP_CHANGE_CONIC_GRADIENT             = 30,
-  OP_LAST
-} OpKind;
-
-
-typedef struct { int value; guint send: 1; }    IntUniformValue;
-typedef struct { float value; guint send: 1; }    FloatUniformValue;
-typedef struct { float value[2]; guint send: 1; } Float2UniformValue;
-typedef struct { GskRoundedRect value; guint send: 1; guint send_corners: 1; } RRUniformValue;
-typedef struct { const GdkRGBA *value; guint send: 1; } RGBAUniformValue;
-typedef struct { const graphene_vec4_t *value; guint send: 1; } Vec4UniformValue;
-typedef struct { const GskColorStop *value; guint send: 1; } ColorStopUniformValue;
-typedef struct { const graphene_matrix_t *value; guint send: 1; } MatrixUniformValue;
-
-/* OpNode are allocated within OpBuffer.pos, but we keep
- * a secondary index into the locations of that buffer
- * from OpBuffer.index. This allows peeking at the kind
- * and quickly replacing existing entries when necessary.
- */
-typedef struct
-{
-  RRUniformValue outline;
-  FloatUniformValue spread;
-  Float2UniformValue offset;
-  RGBAUniformValue color;
-} OpShadow;
-
-typedef struct
-{
-  RRUniformValue outline;
-} OpOutsetShadow;
-
-typedef struct
-{
-  guint  pos;
-  OpKind kind;
-} OpBufferEntry;
-
-typedef struct
-{
-  guint8  *buf;
-  gsize    buflen;
-  gsize    bufpos;
-  GArray  *index;
-} OpBuffer;
-
-typedef struct
-{
-  float opacity;
-} OpOpacity;
-
-typedef struct
-{
-  graphene_matrix_t matrix;
-} OpMatrix;
-
-typedef struct
-{
-  const Program *program;
-} OpProgram;
-
-typedef struct
-{
-  const GdkRGBA *rgba;
-} OpColor;
-
-typedef struct
-{
-  int render_target_id;
-} OpRenderTarget;
-
-typedef struct
-{
-  GskRoundedRect clip;
-  guint send_corners: 1;
-} OpClip;
-
-typedef struct
-{
-  graphene_rect_t viewport;
-} OpViewport;
-
-typedef struct
-{
-  int texture_id;
-} OpTexture;
-
-typedef struct
-{
-  int texture_id;
-  int idx;
-} OpExtraTexture;
-
-typedef struct
-{
-  gsize vao_offset;
-  gsize vao_size;
-} OpDraw;
-
-typedef struct
-{
-  ColorStopUniformValue color_stops;
-  IntUniformValue n_color_stops;
-  float start_point[2];
-  float end_point[2];
-  gboolean repeat;
-} OpLinearGradient;
-
-typedef struct
-{
-  ColorStopUniformValue color_stops;
-  IntUniformValue n_color_stops;
-  float start;
-  float end;
-  float radius[2];
-  float center[2];
-  gboolean repeat;
-} OpRadialGradient;
-
-typedef struct
-{
-  ColorStopUniformValue color_stops;
-  IntUniformValue n_color_stops;
-  float center[2];
-  float angle;
-} OpConicGradient;
-
-typedef struct
-{
-  MatrixUniformValue matrix;
-  Vec4UniformValue offset;
-} OpColorMatrix;
-
-typedef struct
-{
-  float radius;
-  graphene_size_t size;
-  float dir[2];
-} OpBlur;
-
-typedef struct
-{
-  float widths[4];
-  const GdkRGBA *color;
-  GskRoundedRect outline;
-} OpBorder;
-
-typedef struct
-{
-  float progress;
-  int source2;
-} OpCrossFade;
-
-typedef struct
-{
-  char *filename;
-  int width;
-  int height;
-} OpDumpFrameBuffer;
-
-typedef struct
-{
-  char text[64];
-} OpDebugGroup;
-
-typedef struct
-{
-  int source2;
-  int mode;
-} OpBlend;
-
-typedef struct
-{
-  float child_bounds[4];
-  float texture_rect[4];
-} OpRepeat;
-
-typedef struct
-{
-  float size[2];
-  GskGLShader *shader;
-  const guchar *uniform_data;
-} OpGLShader;
-
-void     op_buffer_init            (OpBuffer *buffer);
-void     op_buffer_destroy         (OpBuffer *buffer);
-void     op_buffer_clear           (OpBuffer *buffer);
-gpointer op_buffer_add             (OpBuffer *buffer,
-                                    OpKind    kind);
-
-typedef struct
-{
-  GArray   *index;
-  OpBuffer *buffer;
-  guint     pos;
-} OpBufferIter;
-
-static inline void
-op_buffer_iter_init (OpBufferIter *iter,
-                     OpBuffer     *buffer)
-{
-  iter->index = buffer->index;
-  iter->buffer = buffer;
-  iter->pos = 1; /* Skip first OP_NONE */
-}
-
-static inline gpointer
-op_buffer_iter_next (OpBufferIter *iter,
-                     OpKind       *kind)
-{
-  const OpBufferEntry *entry;
-
-  if (iter->pos == iter->index->len)
-    return NULL;
-
-  entry = &g_array_index (iter->index, OpBufferEntry, iter->pos);
-
-  iter->pos++;
-
-  *kind = entry->kind;
-  return &iter->buffer->buf[entry->pos];
-}
-
-static inline void
-op_buffer_pop_tail (OpBuffer *buffer)
-{
-  /* Never truncate the first OP_NONE */
-  if G_LIKELY (buffer->index->len > 0)
-    buffer->index->len--;
-}
-
-static inline gpointer
-op_buffer_peek_tail (OpBuffer *buffer,
-                     OpKind   *kind)
-{
-  const OpBufferEntry *entry;
-
-  entry = &g_array_index (buffer->index, OpBufferEntry, buffer->index->len - 1);
-  *kind = entry->kind;
-  return &buffer->buf[entry->pos];
-}
-
-static inline gpointer
-op_buffer_peek_tail_checked (OpBuffer *buffer,
-                             OpKind    kind)
-{
-  const OpBufferEntry *entry;
-
-  entry = &g_array_index (buffer->index, OpBufferEntry, buffer->index->len - 1);
-
-  if (entry->kind == kind)
-    return &buffer->buf[entry->pos];
-
-  return NULL;
-}
-
-static inline guint
-op_buffer_n_ops (OpBuffer *buffer)
-{
-  return buffer->index->len - 1;
-}
-
-#endif /* __OP_BUFFER_H__ */
diff --git a/gsk/gl/resources/blend.glsl b/gsk/gl/resources/blend.glsl
deleted file mode 100644 (file)
index 2232340..0000000
+++ /dev/null
@@ -1,310 +0,0 @@
-// VERTEX_SHADER:
-void main() {
-  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
-
-  vUv = vec2(aUv.x, aUv.y);
-}
-
-// FRAGMENT_SHADER:
-uniform int u_mode;
-uniform sampler2D u_source2;
-
-float
-combine (float source, float backdrop)
-{
-  return source + backdrop * (1.0 - source);
-}
-
-vec4
-composite (vec4 Cs, vec4 Cb, vec3 B)
-{
-  float ao = Cs.a + Cb.a * (1.0 - Cs.a);
-  vec3 Co = (Cs.a*(1.0 - Cb.a)*Cs.rgb + Cs.a*Cb.a*B + (1.0 - Cs.a)*Cb.a*Cb.rgb) / ao;
-  return vec4(Co, ao);
-}
-
-vec4
-normal (vec4 Cs, vec4 Cb)
-{
-  return composite (Cs, Cb, Cs.rgb);
-}
-
-vec4
-multiply (vec4 Cs, vec4 Cb)
-{
-  return composite (Cs, Cb, Cs.rgb * Cb.rgb);
-}
-
-vec4
-difference (vec4 Cs, vec4 Cb)
-{
-  return composite (Cs, Cb, abs(Cs.rgb - Cb.rgb));
-}
-
-vec4
-screen (vec4 Cs, vec4 Cb)
-{
-  return composite (Cs, Cb, Cs.rgb + Cb.rgb - Cs.rgb * Cb.rgb);
-}
-
-float
-hard_light (float source, float backdrop)
-{
-  if (source <= 0.5)
-    return 2.0 * backdrop * source;
-  else
-    return 2.0 * (backdrop + source - backdrop * source) - 1.0;
-}
-
-vec4
-hard_light (vec4 Cs, vec4 Cb)
-{
-  vec3 B = vec3 (hard_light (Cs.r, Cb.r),
-                 hard_light (Cs.g, Cb.g),
-                 hard_light (Cs.b, Cb.b));
-  return composite (Cs, Cb, B);
-}
-
-float
-soft_light (float source, float backdrop)
-{
-  float db;
-
-  if (backdrop <= 0.25)
-    db = ((16.0 * backdrop - 12.0) * backdrop + 4.0) * backdrop;
-  else
-    db = sqrt (backdrop);
-
-  if (source <= 0.5)
-    return backdrop - (1.0 - 2.0 * source) * backdrop * (1.0 - backdrop);
-  else
-    return backdrop + (2.0 * source - 1.0) * (db - backdrop);
-}
-
-vec4
-soft_light (vec4 Cs, vec4 Cb)
-{
-  vec3 B = vec3 (soft_light (Cs.r, Cb.r),
-                 soft_light (Cs.g, Cb.g),
-                 soft_light (Cs.b, Cb.b));
-  return composite (Cs, Cb, B);
-}
-
-vec4
-overlay (vec4 Cs, vec4 Cb)
-{
-  vec3 B = vec3 (hard_light (Cb.r, Cs.r),
-                 hard_light (Cb.g, Cs.g),
-                 hard_light (Cb.b, Cs.b));
-  return composite (Cs, Cb, B);
-}
-
-vec4
-darken (vec4 Cs, vec4 Cb)
-{
-  vec3 B = min (Cs.rgb, Cb.rgb);
-  return composite (Cs, Cb, B);
-}
-
-vec4
-lighten (vec4 Cs, vec4 Cb)
-{
-  vec3 B = max (Cs.rgb, Cb.rgb);
-  return composite (Cs, Cb, B);
-}
-
-float
-color_dodge (float source, float backdrop)
-{
-  return (source == 1.0) ? source : min (backdrop / (1.0 - source), 1.0);
-}
-
-vec4
-color_dodge (vec4 Cs, vec4 Cb)
-{
-  vec3 B = vec3 (color_dodge (Cs.r, Cb.r),
-                 color_dodge (Cs.g, Cb.g),
-                 color_dodge (Cs.b, Cb.b));
-  return composite (Cs, Cb, B);
-}
-
-
-float
-color_burn (float source, float backdrop)
-{
-  return (source == 0.0) ? source : max ((1.0 - ((1.0 - backdrop) / source)), 0.0);
-}
-
-vec4
-color_burn (vec4 Cs, vec4 Cb)
-{
-  vec3 B = vec3 (color_burn (Cs.r, Cb.r),
-                 color_burn (Cs.g, Cb.g),
-                 color_burn (Cs.b, Cb.b));
-  return composite (Cs, Cb, B);
-}
-
-vec4
-exclusion (vec4 Cs, vec4 Cb)
-{
-  vec3 B = Cb.rgb + Cs.rgb - 2.0 * Cb.rgb * Cs.rgb;
-  return composite (Cs, Cb, B);
-}
-
-float
-lum (vec3 c)
-{
-  return 0.3 * c.r + 0.59 * c.g + 0.11 * c.b;
-}
-
-vec3
-clip_color (vec3 c)
-{
-  float l = lum (c);
-  float n = min (c.r, min (c.g, c.b));
-  float x = max (c.r, max (c.g, c.b));
-  if (n < 0.0) c = l + (((c - l) * l) / (l - n));
-  if (x > 1.0) c = l + (((c - l) * (1.0 - l)) / (x - l));
-  return c;
-}
-
-vec3
-set_lum (vec3 c, float l)
-{
-  float d = l - lum (c);
-  return clip_color (vec3 (c.r + d, c.g + d, c.b + d));
-}
-
-float
-sat (vec3 c)
-{
-  return max (c.r, max (c.g, c.b)) - min (c.r, min (c.g, c.b));
-}
-
-vec3
-set_sat (vec3 c, float s)
-{
-  float cmin = min (c.r, min (c.g, c.b));
-  float cmax = max (c.r, max (c.g, c.b));
-  vec3 res;
-
-  if (cmax == cmin)
-    res = vec3 (0, 0, 0);
-  else
-    {
-      if (c.r == cmax)
-        {
-          if (c.g == cmin)
-            {
-              res.b = ((c.b - cmin) * s) / (cmax - cmin);
-              res.g = 0.0;
-            }
-          else
-            {
-              res.g = ((c.g - cmin) * s) / (cmax - cmin);
-              res.b = 0.0;
-            }
-          res.r = s;
-        }
-      else if (c.g == cmax)
-        {
-          if (c.r == cmin)
-            {
-              res.b = ((c.b - cmin) * s) / (cmax - cmin);
-              res.r = 0.0;
-            }
-          else
-            {
-              res.r = ((c.r - cmin) * s) / (cmax - cmin);
-              res.b = 0.0;
-            }
-          res.g = s;
-        }
-      else
-        {
-          if (c.r == cmin)
-            {
-              res.g = ((c.g - cmin) * s) / (cmax - cmin);
-              res.r = 0.0;
-            }
-          else
-            {
-              res.r = ((c.r - cmin) * s) / (cmax - cmin);
-              res.g = 0.0;
-            }
-          res.b = s;
-        }
-    }
-  return res;
-}
-
-vec4
-color (vec4 Cs, vec4 Cb)
-{
-  vec3 B = set_lum (Cs.rgb, lum (Cb.rgb));
-  return composite (Cs, Cb, B);
-}
-
-vec4
-hue (vec4 Cs, vec4 Cb)
-{
-  vec3 B = set_lum (set_sat (Cs.rgb, sat (Cb.rgb)), lum (Cb.rgb));
-  return composite (Cs, Cb, B);
-}
-
-vec4
-saturation (vec4 Cs, vec4 Cb)
-{
-  vec3 B = set_lum (set_sat (Cb.rgb, sat (Cs.rgb)), lum (Cb.rgb));
-  return composite (Cs, Cb, B);
-}
-
-vec4
-luminosity (vec4 Cs, vec4 Cb)
-{
-  vec3 B = set_lum (Cb.rgb, lum (Cs.rgb));
-  return composite (Cs, Cb, B);
-}
-
-void main() {
-  vec4 bottom_color = GskTexture(u_source, vUv);
-  vec4 top_color = GskTexture(u_source2, vUv);
-
-  vec4 result;
-  if (u_mode == 0)
-    result = normal(top_color, bottom_color);
-  else if (u_mode == 1)
-    result = multiply(top_color, bottom_color);
-  else if (u_mode == 2)
-    result = screen(top_color, bottom_color);
-  else if (u_mode == 3)
-    result = overlay(top_color, bottom_color);
-  else if (u_mode == 4)
-    result = darken(top_color, bottom_color);
-  else if (u_mode == 5)
-    result = lighten(top_color, bottom_color);
-  else if (u_mode == 6)
-    result = color_dodge(top_color, bottom_color);
-  else if (u_mode == 7)
-    result = color_burn(top_color, bottom_color);
-  else if (u_mode == 8)
-    result = hard_light(top_color, bottom_color);
-  else if (u_mode == 9)
-    result = soft_light(top_color, bottom_color);
-  else if (u_mode == 10)
-    result = difference(top_color, bottom_color);
-  else if (u_mode == 11)
-    result = exclusion(top_color, bottom_color);
-  else if (u_mode == 12)
-    result = color(top_color, bottom_color);
-  else if (u_mode == 13)
-    result = hue(top_color, bottom_color);
-  else if (u_mode == 14)
-    result = saturation(top_color, bottom_color);
-  else if (u_mode == 15)
-    result = luminosity(top_color, bottom_color);
-  else
-    discard;
-
-  gskSetOutputColor(result * u_alpha);
-}
diff --git a/gsk/gl/resources/blit.glsl b/gsk/gl/resources/blit.glsl
deleted file mode 100644 (file)
index f01cd23..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-// VERTEX_SHADER:
-void main() {
-  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
-
-  vUv = vec2(aUv.x, aUv.y);
-}
-
-// FRAGMENT_SHADER:
-void main() {
-  vec4 diffuse = GskTexture(u_source, vUv);
-
-  gskSetOutputColor(diffuse * u_alpha);
-}
diff --git a/gsk/gl/resources/blur.glsl b/gsk/gl/resources/blur.glsl
deleted file mode 100644 (file)
index f782ab4..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-// VERTEX_SHADER:
-uniform float u_blur_radius;
-uniform vec2 u_blur_size;
-uniform vec2 u_blur_dir;
-
-_OUT_ vec2 pixel_step;
-_OUT_ float pixels_per_side;
-_OUT_ vec3 initial_gaussian;
-
-const float PI = 3.14159265;
-const float RADIUS_MULTIPLIER = 2.0;
-
-void main() {
-  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
-
-  vUv = vec2(aUv.x, aUv.y);
-
-  pixel_step = (vec2(1.0) / u_blur_size) * u_blur_dir;
-  pixels_per_side = floor(u_blur_radius * RADIUS_MULTIPLIER / 2.0);
-
-  float sigma = u_blur_radius / 2.0; // *shrug*
-  initial_gaussian.x = 1.0 / (sqrt(2.0 * PI) * sigma);
-  initial_gaussian.y = exp(-0.5 / (sigma * sigma));
-  initial_gaussian.z = initial_gaussian.y * initial_gaussian.y;
-}
-
-// FRAGMENT_SHADER:
-_IN_ vec2 pixel_step;
-_IN_ float pixels_per_side;
-_IN_ vec3 initial_gaussian;
-
-// blur_radius 0 is NOT supported and MUST be caught before.
-
-// Partially from http://callumhay.blogspot.com/2010/09/gaussian-blur-shader-glsl.html
-void main() {
-  vec3 incrementalGaussian = initial_gaussian;
-
-  float coefficientSum = 0.0;
-  vec4 sum = GskTexture(u_source, vUv) * incrementalGaussian.x;
-  coefficientSum += incrementalGaussian.x;
-  incrementalGaussian.xy *= incrementalGaussian.yz;
-
-  vec2 p = pixel_step;
-  for (int i = 1; i <= int(pixels_per_side); i++) {
-    sum += GskTexture(u_source, vUv - p) * incrementalGaussian.x;
-    sum += GskTexture(u_source, vUv + p) * incrementalGaussian.x;
-
-    coefficientSum += 2.0 * incrementalGaussian.x;
-    incrementalGaussian.xy *= incrementalGaussian.yz;
-
-    p += pixel_step;
-  }
-
-  gskSetOutputColor(sum / coefficientSum);
-}
diff --git a/gsk/gl/resources/border.glsl b/gsk/gl/resources/border.glsl
deleted file mode 100644 (file)
index 677a0df..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-// VERTEX_SHADER:
-uniform vec4 u_color;
-uniform vec4 u_widths;
-uniform vec4[3] u_outline_rect;
-
-_OUT_ vec4 final_color;
-_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
-_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
-
-void main() {
-  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
-
-  final_color = gsk_premultiply(u_color) * u_alpha;
-
-  GskRoundedRect outside = gsk_create_rect(u_outline_rect);
-  GskRoundedRect inside = gsk_rounded_rect_shrink (outside, u_widths);
-
-  gsk_rounded_rect_transform(outside, u_modelview);
-  gsk_rounded_rect_transform(inside, u_modelview);
-
-  gsk_rounded_rect_encode(outside, transformed_outside_outline);
-  gsk_rounded_rect_encode(inside, transformed_inside_outline);
-}
-
-// FRAGMENT_SHADER:
-uniform vec4[3] u_outline_rect;
-
-_IN_ vec4 final_color;
-_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
-_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
-
-void main() {
-  vec2 frag = gsk_get_frag_coord();
-
-  float alpha = clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag) -
-                      gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag),
-                      0.0, 1.0);
-
-  gskSetOutputColor(final_color * alpha);
-}
diff --git a/gsk/gl/resources/color.glsl b/gsk/gl/resources/color.glsl
deleted file mode 100644 (file)
index 636456c..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-// VERTEX_SHADER:
-uniform vec4 u_color;
-
-_OUT_ vec4 final_color;
-
-void main() {
-  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
-
-  final_color = gsk_premultiply(u_color) * u_alpha;
-}
-
-// FRAGMENT_SHADER:
-_IN_ vec4 final_color;
-
-void main() {
-  gskSetOutputColor(final_color);
-}
-
diff --git a/gsk/gl/resources/color_matrix.glsl b/gsk/gl/resources/color_matrix.glsl
deleted file mode 100644 (file)
index 79cb364..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// VERTEX_SHADER:
-void main() {
-  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
-
-  vUv = vec2(aUv.x, aUv.y);
-}
-
-// FRAGMENT_SHADER:
-uniform mat4 u_color_matrix;
-uniform vec4 u_color_offset;
-
-void main() {
-  vec4 color = GskTexture(u_source, vUv);
-
-  // Un-premultilpy
-  if (color.a != 0.0)
-    color.rgb /= color.a;
-
-  color = u_color_matrix * color + u_color_offset;
-  color = clamp(color, 0.0, 1.0);
-
-  color.rgb *= color.a;
-
-  gskSetOutputColor(color * u_alpha);
-}
diff --git a/gsk/gl/resources/coloring.glsl b/gsk/gl/resources/coloring.glsl
deleted file mode 100644 (file)
index a675493..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-// VERTEX_SHADER:
-uniform vec4 u_color;
-
-_OUT_ vec4 final_color;
-
-void main() {
-  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
-
-  vUv = vec2(aUv.x, aUv.y);
-
-  final_color = gsk_premultiply(u_color) * u_alpha;
-}
-
-// FRAGMENT_SHADER:
-
-_IN_ vec4 final_color;
-
-void main() {
-  vec4 diffuse = GskTexture(u_source, vUv);
-
-  gskSetOutputColor(final_color * diffuse.a);
-}
diff --git a/gsk/gl/resources/conic_gradient.glsl b/gsk/gl/resources/conic_gradient.glsl
deleted file mode 100644 (file)
index 630a42c..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-// VERTEX_SHADER
-uniform vec4 u_geometry;
-
-_NOPERSPECTIVE_ _OUT_ vec2 coord;
-
-void main() {
-  gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0));
-
-  vec2 mv0 = u_modelview[0].xy;
-  vec2 mv1 = u_modelview[1].xy;
-  vec2 offset = aPosition - u_geometry.xy;
-
-  coord = vec2(dot(mv0, offset),
-               dot(mv1, offset));
-}
-
-// FRAGMENT_SHADER:
-#ifdef GSK_LEGACY
-uniform int u_num_color_stops;
-#else
-uniform highp int u_num_color_stops; // Why? Because it works like this.
-#endif
-
-uniform vec4 u_geometry;
-uniform float u_color_stops[6 * 5];
-
-_NOPERSPECTIVE_ _IN_ vec2 coord;
-
-float get_offset(int index) {
-  return u_color_stops[5 * index];
-}
-
-vec4 get_color(int index) {
-  int base = 5 * index + 1;
-
-  return vec4(u_color_stops[base],
-              u_color_stops[base + 1],
-              u_color_stops[base + 2],
-              u_color_stops[base + 3]);
-}
-
-void main() {
-  // direction of point in range [-PI, PI]
-  vec2 pos = floor(coord);
-  float angle = atan(pos.y, pos.x);
-
-  // fract() does the modulo here, so now we have progress
-  // into the current conic
-  float offset = fract(angle * u_geometry.z + u_geometry.w);
-
-  if (offset < get_offset(0)) {
-    gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha));
-    return;
-  }
-
-  int n = u_num_color_stops - 1;
-  for (int i = 0; i < n; i++) {
-    float curr_offset = get_offset(i);
-    float next_offset = get_offset(i + 1);
-
-    if (offset >= curr_offset && offset < next_offset) {
-      float f = (offset - curr_offset) / (next_offset - curr_offset);
-      vec4 curr_color = gsk_premultiply(get_color(i));
-      vec4 next_color = gsk_premultiply(get_color(i + 1));
-      vec4 color = mix(curr_color, next_color, f);
-
-      gskSetOutputColor(color * u_alpha);
-      return;
-    }
-  }
-
-  gskSetOutputColor(gsk_scaled_premultiply(get_color(n), u_alpha));
-}
diff --git a/gsk/gl/resources/cross_fade.glsl b/gsk/gl/resources/cross_fade.glsl
deleted file mode 100644 (file)
index f824430..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-// VERTEX_SHADER:
-void main() {
-  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
-
-  vUv = vec2(aUv.x, aUv.y);
-}
-
-// FRAGMENT_SHADER:
-uniform float u_progress;
-uniform sampler2D u_source2;
-
-void main() {
-  vec4 source1 = GskTexture(u_source, vUv);  // start child
-  vec4 source2 = GskTexture(u_source2, vUv); // end child
-
-  float p_start = (1.0 - u_progress) * u_alpha;
-  float p_end = u_progress * u_alpha;
-  vec4 color = (p_start * source1) + (p_end * source2);
-  gskSetOutputColor(color);
-}
diff --git a/gsk/gl/resources/custom.glsl b/gsk/gl/resources/custom.glsl
deleted file mode 100644 (file)
index d2aed97..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// VERTEX_SHADER:
-void main() {
-  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
-  vUv = vec2(aUv.x, aUv.y);
-}
-
-// FRAGMENT_SHADER:
-// The shader supplies:
-void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv);
-
-uniform vec2 u_size;
-uniform sampler2D u_source2;
-uniform sampler2D u_source3;
-uniform sampler2D u_source4;
-
-void main() {
-  vec4 fragColor;
-  vec2 fragCoord = vec2(vUv.x * u_size.x, (1.0-vUv.y) * u_size.y);
-  mainImage(fragColor, fragCoord, u_size, vUv);
-  gskSetOutputColor(fragColor);
-}
diff --git a/gsk/gl/resources/inset_shadow.glsl b/gsk/gl/resources/inset_shadow.glsl
deleted file mode 100644 (file)
index 9a21cde..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-// VERTEX_SHADER:
-uniform vec4 u_color;
-uniform float u_spread;
-uniform vec2 u_offset;
-uniform vec4[3] u_outline_rect;
-
-_OUT_ vec4 final_color;
-_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
-_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
-
-void main() {
-  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
-
-  final_color = gsk_premultiply(u_color) * u_alpha;
-
-  GskRoundedRect outside = gsk_create_rect(u_outline_rect);
-  GskRoundedRect inside = gsk_rounded_rect_shrink(outside, vec4(u_spread));
-
-  gsk_rounded_rect_offset(inside, u_offset);
-
-  gsk_rounded_rect_transform(outside, u_modelview);
-  gsk_rounded_rect_transform(inside, u_modelview);
-
-  gsk_rounded_rect_encode(outside, transformed_outside_outline);
-  gsk_rounded_rect_encode(inside, transformed_inside_outline);
-}
-
-// FRAGMENT_SHADER:
-_IN_ vec4 final_color;
-_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
-_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
-
-void main() {
-  vec2 frag = gsk_get_frag_coord();
-
-  float alpha = clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag) -
-                      gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag),
-                      0.0, 1.0);
-
-  gskSetOutputColor(final_color * alpha);
-}
diff --git a/gsk/gl/resources/linear_gradient.glsl b/gsk/gl/resources/linear_gradient.glsl
deleted file mode 100644 (file)
index cc90392..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-// VERTEX_SHADER
-uniform vec4 u_points;
-
-_NOPERSPECTIVE_ _OUT_ vec4 info;
-
-void main() {
-  gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0));
-
-  vec2 mv0 = u_modelview[0].xy;
-  vec2 mv1 = u_modelview[1].xy;
-  vec2 offset = aPosition - u_points.xy;
-  vec2 coord = vec2(dot(mv0, offset),
-                    dot(mv1, offset));
-
-  // Original equation:
-  // VS | maxDist = length(end - start);
-  // VS | gradient = end - start;
-  // VS | gradientLength = length(gradient);
-  // FS | pos = frag_coord - start
-  // FS | proj = (dot(gradient, pos) / (gradientLength * gradientLength)) * gradient
-  // FS | offset = length(proj) / maxDist
-
-  // Simplified formula derivation:
-  // 1. Notice that maxDist = gradientLength:
-  // offset = length(proj) / gradientLength
-  // 2. Let gnorm = gradient / gradientLength, then:
-  // proj = (dot(gnorm * gradientLength, pos) / (gradientLength * gradientLength)) * (gnorm * gradientLength) =
-  //      = dot(gnorm, pos) * gnorm
-  // 3. Since gnorm is unit length then:
-  // length(proj) = length(dot(gnorm, pos) * gnorm) = dot(gnorm, pos)
-  // 4. We can avoid the FS division by passing a scaled pos from the VS:
-  // offset = dot(gnorm, pos) / gradientLength = dot(gnorm, pos / gradientLength)
-  // 5. 1.0 / length(gradient) is inversesqrt(dot(gradient, gradient)) in GLSL
-  vec2 gradient = vec2(dot(mv0, u_points.zw),
-                       dot(mv1, u_points.zw));
-  float rcp_gradient_length = inversesqrt(dot(gradient, gradient));
-
-  info = rcp_gradient_length * vec4(coord, gradient);
-}
-
-// FRAGMENT_SHADER:
-#ifdef GSK_LEGACY
-uniform int u_num_color_stops;
-#else
-uniform highp int u_num_color_stops; // Why? Because it works like this.
-#endif
-
-uniform float u_color_stops[6 * 5];
-uniform bool u_repeat;
-
-_NOPERSPECTIVE_ _IN_ vec4 info;
-
-float get_offset(int index) {
-  return u_color_stops[5 * index];
-}
-
-vec4 get_color(int index) {
-  int base = 5 * index + 1;
-
-  return vec4(u_color_stops[base],
-              u_color_stops[base + 1],
-              u_color_stops[base + 2],
-              u_color_stops[base + 3]);
-}
-
-void main() {
-  float offset = dot(info.xy, info.zw);
-
-  if (u_repeat) {
-    offset = fract(offset);
-  }
-
-  if (offset < get_offset(0)) {
-    gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha));
-    return;
-  }
-
-  int n = u_num_color_stops - 1;
-  for (int i = 0; i < n; i++) {
-    float curr_offset = get_offset(i);
-    float next_offset = get_offset(i + 1);
-
-    if (offset >= curr_offset && offset < next_offset) {
-      float f = (offset - curr_offset) / (next_offset - curr_offset);
-      vec4 curr_color = gsk_premultiply(get_color(i));
-      vec4 next_color = gsk_premultiply(get_color(i + 1));
-      vec4 color = mix(curr_color, next_color, f);
-
-      gskSetOutputColor(color * u_alpha);
-      return;
-    }
-  }
-
-  gskSetOutputColor(gsk_scaled_premultiply(get_color(n), u_alpha));
-}
diff --git a/gsk/gl/resources/outset_shadow.glsl b/gsk/gl/resources/outset_shadow.glsl
deleted file mode 100644 (file)
index 373c650..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-// VERTEX_SHADER:
-uniform vec4 u_color;
-uniform vec4[3] u_outline_rect;
-
-_OUT_ vec4 final_color;
-_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outline;
-
-void main() {
-  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
-
-  vUv = vec2(aUv.x, aUv.y);
-
-  final_color = gsk_premultiply(u_color) * u_alpha;
-
-  GskRoundedRect outline = gsk_create_rect(u_outline_rect);
-  gsk_rounded_rect_transform(outline, u_modelview);
-  gsk_rounded_rect_encode(outline, transformed_outline);
-}
-
-// FRAGMENT_SHADER:
-_IN_ vec4 final_color;
-_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outline;
-
-void main() {
-  vec2 frag = gsk_get_frag_coord();
-
-  float alpha = GskTexture(u_source, vUv).a;
-  alpha *= (1.0 -  clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outline), frag), 0.0, 1.0));
-
-  vec4 color = final_color * alpha;
-
-  gskSetOutputColor(color);
-}
diff --git a/gsk/gl/resources/preamble.fs.glsl b/gsk/gl/resources/preamble.fs.glsl
deleted file mode 100644 (file)
index 3a2fe49..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-uniform sampler2D u_source;
-uniform mat4 u_projection;
-uniform mat4 u_modelview;
-uniform float u_alpha;// = 1.0;
-uniform vec4 u_viewport;
-uniform vec4[3] u_clip_rect;
-
-#if defined(GSK_LEGACY)
-_OUT_ vec4 outputColor;
-#elif !defined(GSK_GLES)
-_OUT_ vec4 outputColor;
-#endif
-
-_IN_ vec2 vUv;
-
-
-
-GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r)
-{
-#if defined(GSK_GLES) || defined(GSK_LEGACY)
-  return GskRoundedRect(r[0], r[1], r[2]);
-#else
-  return r;
-#endif
-}
-
-float
-gsk_ellipsis_dist (vec2 p, vec2 radius)
-{
-  if (radius == vec2(0, 0))
-    return 0.0;
-
-  vec2 p0 = p / radius;
-  vec2 p1 = 2.0 * p0 / radius;
-
-  return (dot(p0, p0) - 1.0) / length (p1);
-}
-
-float
-gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius)
-{
-  float d = gsk_ellipsis_dist (point - center, radius);
-  return clamp (0.5 - d, 0.0, 1.0);
-}
-
-float
-gsk_rounded_rect_coverage (GskRoundedRect r, vec2 p)
-{
-  if (p.x < r.bounds.x || p.y < r.bounds.y ||
-      p.x >= r.bounds.z || p.y >= r.bounds.w)
-    return 0.0;
-
-  vec2 ref_tl = r.corner_points1.xy;
-  vec2 ref_tr = r.corner_points1.zw;
-  vec2 ref_br = r.corner_points2.xy;
-  vec2 ref_bl = r.corner_points2.zw;
-
-  if (p.x >= ref_tl.x && p.x >= ref_bl.x &&
-      p.x <= ref_tr.x && p.x <= ref_br.x)
-    return 1.0;
-
-  if (p.y >= ref_tl.y && p.y >= ref_tr.y &&
-      p.y <= ref_bl.y && p.y <= ref_br.y)
-    return 1.0;
-
-  vec2 rad_tl = r.corner_points1.xy - r.bounds.xy;
-  vec2 rad_tr = r.corner_points1.zw - r.bounds.zy;
-  vec2 rad_br = r.corner_points2.xy - r.bounds.zw;
-  vec2 rad_bl = r.corner_points2.zw - r.bounds.xw;
-
-  float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl);
-  float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr);
-  float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br);
-  float d_bl = gsk_ellipsis_coverage(p, ref_bl, rad_bl);
-
-  vec4 corner_coverages = 1.0 - vec4(d_tl, d_tr, d_br, d_bl);
-
-  bvec4 is_out = bvec4(p.x < ref_tl.x && p.y < ref_tl.y,
-                       p.x > ref_tr.x && p.y < ref_tr.y,
-                       p.x > ref_br.x && p.y > ref_br.y,
-                       p.x < ref_bl.x && p.y > ref_bl.y);
-
-  return 1.0 - dot(vec4(is_out), corner_coverages);
-}
-
-float
-gsk_rect_coverage (vec4 r, vec2 p)
-{
-  if (p.x < r.x || p.y < r.y ||
-      p.x >= r.z || p.y >= r.w)
-    return 0.0;
-
-  return 1.0;
-}
-
-vec4 GskTexture(sampler2D sampler, vec2 texCoords) {
-#if defined(GSK_GLES) || defined(GSK_LEGACY)
-  return texture2D(sampler, texCoords);
-#else
-  return texture(sampler, texCoords);
-#endif
-}
-
-#ifdef GSK_GL3
-layout(origin_upper_left) in vec4 gl_FragCoord;
-#endif
-
-vec2 gsk_get_frag_coord() {
-  vec2 fc = gl_FragCoord.xy;
-
-#ifdef GSK_GL3
-  fc += u_viewport.xy;
-#else
-  fc.x += u_viewport.x;
-  fc.y = (u_viewport.y + u_viewport.w) - fc.y;
-#endif
-
-  return fc;
-}
-
-void gskSetOutputColor(vec4 color) {
-  vec4 result;
-
-#if defined(NO_CLIP)
-  result = color;
-#elif defined(RECT_CLIP)
-  result = color * gsk_rect_coverage(gsk_get_bounds(u_clip_rect),
-                                     gsk_get_frag_coord());
-#else
-  result = color * gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect),
-                                             gsk_get_frag_coord());
-#endif
-
-#if defined(GSK_GLES) || defined(GSK_LEGACY)
-  gl_FragColor = result;
-#else
-  outputColor = result;
-#endif
-}
diff --git a/gsk/gl/resources/preamble.glsl b/gsk/gl/resources/preamble.glsl
deleted file mode 100644 (file)
index 8bc007b..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef GSK_LEGACY
-precision highp float;
-#endif
-
-#if defined(GSK_GLES) || defined(GSK_LEGACY)
-#define _OUT_ varying
-#define _IN_ varying
-#define _NOPERSPECTIVE_
-#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3]
-#else
-#define _OUT_ out
-#define _IN_ in
-#define _NOPERSPECTIVE_ noperspective
-#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect
-#endif
-
-
-struct GskRoundedRect
-{
-  vec4 bounds; // Top left and bottom right
-  // Look, arrays can't be in structs if you want to return the struct
-  // from a function in gles or whatever. Just kill me.
-  vec4 corner_points1; // xy = top left, zw = top right
-  vec4 corner_points2; // xy = bottom right, zw = bottom left
-};
-
-// Transform from a C GskRoundedRect to what we need.
-GskRoundedRect
-gsk_create_rect(vec4[3] data)
-{
-  vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw);
-
-  vec4 corner_points1 = vec4(bounds.xy + data[1].xy,
-                             bounds.zy + vec2(data[1].zw * vec2(-1, 1)));
-  vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)),
-                             bounds.xw + vec2(data[2].zw * vec2(1, -1)));
-
-  return GskRoundedRect(bounds, corner_points1, corner_points2);
-}
-
-vec4
-gsk_get_bounds(vec4[3] data)
-{
-  return vec4(data[0].xy, data[0].xy + data[0].zw);
-}
-
-vec4 gsk_premultiply(vec4 c) {
-  return vec4(c.rgb * c.a, c.a);
-}
-
-vec4 gsk_scaled_premultiply(vec4 c, float s) {
-  // Fast version of gsk_premultiply(c) * s
-  // 4 muls instead of 7
-  float a = s * c.a;
-
-  return vec4(c.rgb * a, a);
-}
diff --git a/gsk/gl/resources/preamble.vs.glsl b/gsk/gl/resources/preamble.vs.glsl
deleted file mode 100644 (file)
index 89ee6f7..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-uniform mat4 u_projection;
-uniform mat4 u_modelview;
-uniform float u_alpha;
-
-#if defined(GSK_GLES) || defined(GSK_LEGACY)
-attribute vec2 aPosition;
-attribute vec2 aUv;
-_OUT_ vec2 vUv;
-#else
-_IN_ vec2 aPosition;
-_IN_ vec2 aUv;
-_OUT_ vec2 vUv;
-#endif
-
-// amount is: top, right, bottom, left
-GskRoundedRect
-gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount)
-{
-  vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz;
-  vec4 new_corner_points1 = r.corner_points1;
-  vec4 new_corner_points2 = r.corner_points2;
-
-  if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy;
-  if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy;
-  if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw;
-  if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw;
-
-  return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2);
-}
-
-void
-gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset)
-{
-  r.bounds.xy += offset;
-  r.bounds.zw += offset;
-  r.corner_points1.xy += offset;
-  r.corner_points1.zw += offset;
-  r.corner_points2.xy += offset;
-  r.corner_points2.zw += offset;
-}
-
-void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat)
-{
-  r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy;
-  r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy;
-
-  r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy;
-  r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy;
-
-  r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy;
-  r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy;
-}
-
-#if defined(GSK_LEGACY)
-// Can't have out or inout array parameters...
-#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2;
-#else
-void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r)
-{
-#if defined(GSK_GLES)
-  out_r[0] = r.bounds;
-  out_r[1] = r.corner_points1;
-  out_r[2] = r.corner_points2;
-#else
-  out_r = r;
-#endif
-}
-
-#endif
diff --git a/gsk/gl/resources/radial_gradient.glsl b/gsk/gl/resources/radial_gradient.glsl
deleted file mode 100644 (file)
index 0ab3fdf..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-// VERTEX_SHADER
-uniform vec4 u_geometry;
-
-_NOPERSPECTIVE_ _OUT_ vec2 coord;
-
-void main() {
-  gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0));
-
-  vec2 mv0 = u_modelview[0].xy;
-  vec2 mv1 = u_modelview[1].xy;
-  vec2 offset = aPosition - u_geometry.xy;
-  vec2 dir = vec2(dot(mv0, offset),
-                  dot(mv1, offset));
-
-  coord = dir * u_geometry.zw;
-}
-
-// FRAGMENT_SHADER:
-#ifdef GSK_LEGACY
-uniform int u_num_color_stops;
-#else
-uniform highp int u_num_color_stops;
-#endif
-
-uniform bool u_repeat;
-uniform vec2 u_range;
-uniform float u_color_stops[6 * 5];
-
-_NOPERSPECTIVE_ _IN_ vec2 coord;
-
-float get_offset(int index) {
-  return u_color_stops[5 * index];
-}
-
-vec4 get_color(int index) {
-  int base = 5 * index + 1;
-
-  return vec4(u_color_stops[base],
-              u_color_stops[base + 1],
-              u_color_stops[base + 2],
-              u_color_stops[base + 3]);
-}
-
-void main() {
-  // Reverse scale
-  float offset = length(coord) * u_range.x + u_range.y;
-
-  if (u_repeat) {
-    offset = fract(offset);
-  }
-
-  if (offset < get_offset(0)) {
-    gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha));
-    return;
-  }
-
-  int n = u_num_color_stops - 1;
-  for (int i = 0; i < n; i++) {
-    float curr_offset = get_offset(i);
-    float next_offset = get_offset(i + 1);
-
-    if (offset >= curr_offset && offset < next_offset) {
-      float f = (offset - curr_offset) / (next_offset - curr_offset);
-      vec4 curr_color = gsk_premultiply(get_color(i));
-      vec4 next_color = gsk_premultiply(get_color(i + 1));
-      vec4 color = mix(curr_color, next_color, f);
-
-      gskSetOutputColor(color * u_alpha);
-      return;
-    }
-  }
-
-  gskSetOutputColor(gsk_scaled_premultiply(get_color(n), u_alpha));
-}
diff --git a/gsk/gl/resources/repeat.glsl b/gsk/gl/resources/repeat.glsl
deleted file mode 100644 (file)
index a9ebcc5..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-// VERTEX_SHADER:
-void main() {
-  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
-
-  vUv = vec2(aUv.x, aUv.y);
-}
-
-// FRAGMENT_SHADER:
-uniform vec4 u_child_bounds;
-uniform vec4 u_texture_rect;
-
-
-float wrap(float f, float wrap_for) {
-  return mod(f, wrap_for);
-}
-
-/* We get the texture coordinates via vUv,
- * but that might be on a texture atlas, so we need to do the
- * wrapping ourselves.
- */
-void main() {
-
-  /* We map the texture coordinate to [1;0], then wrap it and scale the result again */
-
-  float tw = u_texture_rect.z - u_texture_rect.x;
-  float th = u_texture_rect.w - u_texture_rect.y;
-
-  float mapped_x = (vUv.x - u_texture_rect.x) / tw;
-  float mapped_y = (vUv.y - u_texture_rect.y) / th;
-
-  float wrapped_x = wrap(u_child_bounds.x + mapped_x * u_child_bounds.z, 1.0);
-  float wrapped_y = wrap(u_child_bounds.y + mapped_y * u_child_bounds.w, 1.0);
-
-  vec2 tp;
-  tp.x = u_texture_rect.x + (wrapped_x * tw);
-  tp.y = u_texture_rect.y + (wrapped_y * th);
-
-  vec4 diffuse = GskTexture(u_source, tp);
-
-  gskSetOutputColor(diffuse * u_alpha);
-}
diff --git a/gsk/gl/resources/unblurred_outset_shadow.glsl b/gsk/gl/resources/unblurred_outset_shadow.glsl
deleted file mode 100644 (file)
index f110370..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-// VERTEX_SHADER:
-uniform vec4 u_color;
-uniform float u_spread;
-uniform vec2 u_offset;
-uniform vec4[3] u_outline_rect;
-
-_OUT_ vec4 final_color;
-_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
-_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
-
-void main() {
-  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
-
-  final_color = gsk_premultiply(u_color) * u_alpha;
-
-  GskRoundedRect inside = gsk_create_rect(u_outline_rect);
-  GskRoundedRect outside = gsk_rounded_rect_shrink(inside, vec4(- u_spread));
-
-  gsk_rounded_rect_offset(outside, u_offset);
-
-  gsk_rounded_rect_transform(outside, u_modelview);
-  gsk_rounded_rect_transform(inside, u_modelview);
-
-  gsk_rounded_rect_encode(outside, transformed_outside_outline);
-  gsk_rounded_rect_encode(inside, transformed_inside_outline);
-}
-
-// FRAGMENT_SHADER:
-_IN_ vec4 final_color;
-_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
-_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
-
-void main() {
-  vec2 frag = gsk_get_frag_coord();
-
-  float alpha = clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag) -
-                      gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag),
-                      0.0, 1.0);
-
-  gskSetOutputColor(final_color * alpha);
-}
-
diff --git a/gsk/gl/stb_rect_pack.c b/gsk/gl/stb_rect_pack.c
deleted file mode 100644 (file)
index ff65846..0000000
+++ /dev/null
@@ -1,431 +0,0 @@
-
-#include "stb_rect_pack.h"
-#define STB_RECT_PACK_IMPLEMENTATION
-//////////////////////////////////////////////////////////////////////////////
-//
-//     IMPLEMENTATION SECTION
-//
-
-#ifdef STB_RECT_PACK_IMPLEMENTATION
-#ifndef STBRP_SORT
-#include <stdlib.h>
-#define STBRP_SORT qsort
-#endif
-
-#ifndef STBRP_ASSERT
-#include <assert.h>
-#define STBRP_ASSERT assert
-#endif
-
-#ifdef _MSC_VER
-#define STBRP__NOTUSED(v)  (void)(v)
-#else
-#define STBRP__NOTUSED(v)  (void)sizeof(v)
-#endif
-
-enum
-{
-   STBRP__INIT_skyline = 1
-};
-
-STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
-{
-   switch (context->init_mode) {
-      case STBRP__INIT_skyline:
-         STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
-         context->heuristic = heuristic;
-         break;
-      default:
-         STBRP_ASSERT(0);
-   }
-}
-
-STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
-{
-   if (allow_out_of_mem)
-      // if it's ok to run out of memory, then don't bother aligning them;
-      // this gives better packing, but may fail due to OOM (even though
-      // the rectangles easily fit). @TODO a smarter approach would be to only
-      // quantize once we've hit OOM, then we could get rid of this parameter.
-      context->align = 1;
-   else {
-      // if it's not ok to run out of memory, then quantize the widths
-      // so that num_nodes is always enough nodes.
-      //
-      // I.e. num_nodes * align >= width
-      //                  align >= width / num_nodes
-      //                  align = ceil(width/num_nodes)
-
-      context->align = (context->width + context->num_nodes-1) / context->num_nodes;
-   }
-}
-
-STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
-{
-   int i;
-#ifndef STBRP_LARGE_RECTS
-   STBRP_ASSERT(width <= 0xffff && height <= 0xffff);
-#endif
-
-   for (i=0; i < num_nodes-1; ++i)
-      nodes[i].next = &nodes[i+1];
-   nodes[i].next = NULL;
-   context->init_mode = STBRP__INIT_skyline;
-   context->heuristic = STBRP_HEURISTIC_Skyline_default;
-   context->free_head = &nodes[0];
-   context->active_head = &context->extra[0];
-   context->width = width;
-   context->height = height;
-   context->num_nodes = num_nodes;
-   stbrp_setup_allow_out_of_mem(context, 0);
-
-   // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
-   context->extra[0].x = 0;
-   context->extra[0].y = 0;
-   context->extra[0].next = &context->extra[1];
-   context->extra[1].x = (stbrp_coord) width;
-#ifdef STBRP_LARGE_RECTS
-   context->extra[1].y = (1<<30);
-#else
-   context->extra[1].y = 65535;
-#endif
-   context->extra[1].next = NULL;
-}
-
-// find minimum y position if it starts at x1
-static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
-{
-   stbrp_node *node = first;
-   int x1 = x0 + width;
-   int min_y, visited_width, waste_area;
-
-   STBRP__NOTUSED(c);
-
-   STBRP_ASSERT(first->x <= x0);
-
-   #if 0
-   // skip in case we're past the node
-   while (node->next->x <= x0)
-      ++node;
-   #else
-   STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
-   #endif
-
-   STBRP_ASSERT(node->x <= x0);
-
-   min_y = 0;
-   waste_area = 0;
-   visited_width = 0;
-   while (node->x < x1) {
-      if (node->y > min_y) {
-         // raise min_y higher.
-         // we've accounted for all waste up to min_y,
-         // but we'll now add more waste for everything we've visited
-         waste_area += visited_width * (node->y - min_y);
-         min_y = node->y;
-         // the first time through, visited_width might be reduced
-         if (node->x < x0)
-            visited_width += node->next->x - x0;
-         else
-            visited_width += node->next->x - node->x;
-      } else {
-         // add waste area
-         int under_width = node->next->x - node->x;
-         if (under_width + visited_width > width)
-            under_width = width - visited_width;
-         waste_area += under_width * (min_y - node->y);
-         visited_width += under_width;
-      }
-      node = node->next;
-   }
-
-   *pwaste = waste_area;
-   return min_y;
-}
-
-typedef struct
-{
-   int x,y;
-   stbrp_node **prev_link;
-} stbrp__findresult;
-
-static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
-{
-   int best_waste = (1<<30), best_x, best_y = (1 << 30);
-   stbrp__findresult fr;
-   stbrp_node **prev, *node, *tail, **best = NULL;
-
-   // align to multiple of c->align
-   width = (width + c->align - 1);
-   width -= width % c->align;
-   STBRP_ASSERT(width % c->align == 0);
-
-   node = c->active_head;
-   prev = &c->active_head;
-   while (node->x + width <= c->width) {
-      int y,waste;
-      y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
-      if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
-         // bottom left
-         if (y < best_y) {
-            best_y = y;
-            best = prev;
-         }
-      } else {
-         // best-fit
-         if (y + height <= c->height) {
-            // can only use it if it first vertically
-            if (y < best_y || (y == best_y && waste < best_waste)) {
-               best_y = y;
-               best_waste = waste;
-               best = prev;
-            }
-         }
-      }
-      prev = &node->next;
-      node = node->next;
-   }
-
-   best_x = (best == NULL) ? 0 : (*best)->x;
-
-   // if doing best-fit (BF), we also have to try aligning right edge to each node position
-   //
-   // e.g, if fitting
-   //
-   //     ____________________
-   //    |____________________|
-   //
-   //            into
-   //
-   //   |                         |
-   //   |             ____________|
-   //   |____________|
-   //
-   // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
-   //
-   // This makes BF take about 2x the time
-
-   if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
-      tail = c->active_head;
-      node = c->active_head;
-      prev = &c->active_head;
-      // find first node that's admissible
-      while (tail->x < width)
-         tail = tail->next;
-      while (tail) {
-         int xpos = tail->x - width;
-         int y,waste;
-         STBRP_ASSERT(xpos >= 0);
-         // find the left position that matches this
-         while (node->next->x <= xpos) {
-            prev = &node->next;
-            node = node->next;
-         }
-         STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
-         y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
-         if (y + height < c->height) {
-            if (y <= best_y) {
-               if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
-                  best_x = xpos;
-                  STBRP_ASSERT(y <= best_y);
-                  best_y = y;
-                  best_waste = waste;
-                  best = prev;
-               }
-            }
-         }
-         tail = tail->next;
-      }
-   }
-
-   fr.prev_link = best;
-   fr.x = best_x;
-   fr.y = best_y;
-   return fr;
-}
-
-static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
-{
-   // find best position according to heuristic
-   stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
-   stbrp_node *node, *cur;
-
-   // bail if:
-   //    1. it failed
-   //    2. the best node doesn't fit (we don't always check this)
-   //    3. we're out of memory
-   if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
-      res.prev_link = NULL;
-      return res;
-   }
-
-   // on success, create new node
-   node = context->free_head;
-   node->x = (stbrp_coord) res.x;
-   node->y = (stbrp_coord) (res.y + height);
-
-   context->free_head = node->next;
-
-   // insert the new node into the right starting point, and
-   // let 'cur' point to the remaining nodes needing to be
-   // stiched back in
-
-   cur = *res.prev_link;
-   if (cur->x < res.x) {
-      // preserve the existing one, so start testing with the next one
-      stbrp_node *next = cur->next;
-      cur->next = node;
-      cur = next;
-   } else {
-      *res.prev_link = node;
-   }
-
-   // from here, traverse cur and free the nodes, until we get to one
-   // that shouldn't be freed
-   while (cur->next && cur->next->x <= res.x + width) {
-      stbrp_node *next = cur->next;
-      // move the current node to the free list
-      cur->next = context->free_head;
-      context->free_head = cur;
-      cur = next;
-   }
-
-   // stitch the list back in
-   node->next = cur;
-
-   if (cur->x < res.x + width)
-      cur->x = (stbrp_coord) (res.x + width);
-
-#ifdef _DEBUG
-   cur = context->active_head;
-   while (cur->x < context->width) {
-      STBRP_ASSERT(cur->x < cur->next->x);
-      cur = cur->next;
-   }
-   STBRP_ASSERT(cur->next == NULL);
-
-   {
-      int count=0;
-      cur = context->active_head;
-      while (cur) {
-         cur = cur->next;
-         ++count;
-      }
-      cur = context->free_head;
-      while (cur) {
-         cur = cur->next;
-         ++count;
-      }
-      STBRP_ASSERT(count == context->num_nodes+2);
-   }
-#endif
-
-   return res;
-}
-
-static int rect_height_compare(const void *a, const void *b)
-{
-   const stbrp_rect *p = (const stbrp_rect *) a;
-   const stbrp_rect *q = (const stbrp_rect *) b;
-   if (p->h > q->h)
-      return -1;
-   if (p->h < q->h)
-      return  1;
-   return (p->w > q->w) ? -1 : (p->w < q->w);
-}
-
-static int rect_original_order(const void *a, const void *b)
-{
-   const stbrp_rect *p = (const stbrp_rect *) a;
-   const stbrp_rect *q = (const stbrp_rect *) b;
-   return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
-}
-
-#ifdef STBRP_LARGE_RECTS
-#define STBRP__MAXVAL  0xffffffff
-#else
-#define STBRP__MAXVAL  0xffff
-#endif
-
-STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
-{
-   int i, all_rects_packed = 1;
-
-   // we use the 'was_packed' field internally to allow sorting/unsorting
-   for (i=0; i < num_rects; ++i) {
-      rects[i].was_packed = i;
-   }
-
-   // sort according to heuristic
-   STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
-
-   for (i=0; i < num_rects; ++i) {
-      if (rects[i].w == 0 || rects[i].h == 0) {
-         rects[i].x = rects[i].y = 0;  // empty rect needs no space
-      } else {
-         stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
-         if (fr.prev_link) {
-            rects[i].x = (stbrp_coord) fr.x;
-            rects[i].y = (stbrp_coord) fr.y;
-         } else {
-            rects[i].x = rects[i].y = STBRP__MAXVAL;
-         }
-      }
-   }
-
-   // unsort
-   STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
-
-   // set was_packed flags and all_rects_packed status
-   for (i=0; i < num_rects; ++i) {
-      rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
-      if (!rects[i].was_packed)
-         all_rects_packed = 0;
-   }
-
-   // return the all_rects_packed status
-   return all_rects_packed;
-}
-#endif
-
-/*
-------------------------------------------------------------------------------
-This software is available under 2 licenses -- choose whichever you prefer.
-------------------------------------------------------------------------------
-ALTERNATIVE A - MIT License
-Copyright (c) 2017 Sean Barrett
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-------------------------------------------------------------------------------
-ALTERNATIVE B - Public Domain (www.unlicense.org)
-This is free and unencumbered software released into the public domain.
-Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
-software, either in source code form or as a compiled binary, for any purpose,
-commercial or non-commercial, and by any means.
-In jurisdictions that recognize copyright laws, the author or authors of this
-software dedicate any and all copyright interest in the software to the public
-domain. We make this dedication for the benefit of the public at large and to
-the detriment of our heirs and successors. We intend this dedication to be an
-overt act of relinquishment in perpetuity of all present and future rights to
-this software under copyright law.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-------------------------------------------------------------------------------
-*/
diff --git a/gsk/gl/stb_rect_pack.h b/gsk/gl/stb_rect_pack.h
deleted file mode 100644 (file)
index 3ecb1c2..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-// stb_rect_pack.h - v0.99 - public domain - rectangle packing
-// Sean Barrett 2014
-//
-// Useful for e.g. packing rectangular textures into an atlas.
-// Does not do rotation.
-//
-// Not necessarily the awesomest packing method, but better than
-// the totally naive one in stb_truetype (which is primarily what
-// this is meant to replace).
-//
-// Has only had a few tests run, may have issues.
-//
-// More docs to come.
-//
-// No memory allocations; uses qsort() and assert() from stdlib.
-// Can override those by defining STBRP_SORT and STBRP_ASSERT.
-//
-// This library currently uses the Skyline Bottom-Left algorithm.
-//
-// Please note: better rectangle packers are welcome! Please
-// implement them to the same API, but with a different init
-// function.
-//
-// Credits
-//
-//  Library
-//    Sean Barrett
-//  Minor features
-//    Martins Mozeiko
-//    github:IntellectualKitty
-//
-//  Bugfixes / warning fixes
-//    Jeremy Jaussaud
-//
-// Version history:
-//
-//     0.99  (2019-02-07)  warning fixes
-//     0.11  (2017-03-03)  return packing success/fail result
-//     0.10  (2016-10-25)  remove cast-away-const to avoid warnings
-//     0.09  (2016-08-27)  fix compiler warnings
-//     0.08  (2015-09-13)  really fix bug with empty rects (w=0 or h=0)
-//     0.07  (2015-09-13)  fix bug with empty rects (w=0 or h=0)
-//     0.06  (2015-04-15)  added STBRP_SORT to allow replacing qsort
-//     0.05:  added STBRP_ASSERT to allow replacing assert
-//     0.04:  fixed minor bug in STBRP_LARGE_RECTS support
-//     0.01:  initial release
-//
-// LICENSE
-//
-//   See end of file for license information.
-
-//////////////////////////////////////////////////////////////////////////////
-//
-//       INCLUDE SECTION
-//
-
-#ifndef STB_INCLUDE_STB_RECT_PACK_H
-#define STB_INCLUDE_STB_RECT_PACK_H
-
-#define STB_RECT_PACK_VERSION  1
-
-#ifdef STBRP_STATIC
-#define STBRP_DEF static
-#else
-#define STBRP_DEF extern
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct stbrp_context stbrp_context;
-typedef struct stbrp_node    stbrp_node;
-typedef struct stbrp_rect    stbrp_rect;
-
-#ifdef STBRP_LARGE_RECTS
-typedef int            stbrp_coord;
-#else
-typedef unsigned short stbrp_coord;
-#endif
-
-STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
-// Assign packed locations to rectangles. The rectangles are of type
-// 'stbrp_rect' defined below, stored in the array 'rects', and there
-// are 'num_rects' many of them.
-//
-// Rectangles which are successfully packed have the 'was_packed' flag
-// set to a non-zero value and 'x' and 'y' store the minimum location
-// on each axis (i.e. bottom-left in cartesian coordinates, top-left
-// if you imagine y increasing downwards). Rectangles which do not fit
-// have the 'was_packed' flag set to 0.
-//
-// You should not try to access the 'rects' array from another thread
-// while this function is running, as the function temporarily reorders
-// the array while it executes.
-//
-// To pack into another rectangle, you need to call stbrp_init_target
-// again. To continue packing into the same rectangle, you can call
-// this function again. Calling this multiple times with multiple rect
-// arrays will probably produce worse packing results than calling it
-// a single time with the full rectangle array, but the option is
-// available.
-//
-// The function returns 1 if all of the rectangles were successfully
-// packed and 0 otherwise.
-
-struct stbrp_rect
-{
-   // reserved for your use:
-   int            id;
-
-   // input:
-   stbrp_coord    w, h;
-
-   // output:
-   stbrp_coord    x, y;
-   int            was_packed;  // non-zero if valid packing
-
-}; // 16 bytes, nominally
-
-
-STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
-// Initialize a rectangle packer to:
-//    pack a rectangle that is 'width' by 'height' in dimensions
-//    using temporary storage provided by the array 'nodes', which is 'num_nodes' long
-//
-// You must call this function every time you start packing into a new target.
-//
-// There is no "shutdown" function. The 'nodes' memory must stay valid for
-// the following stbrp_pack_rects() call (or calls), but can be freed after
-// the call (or calls) finish.
-//
-// Note: to guarantee best results, either:
-//       1. make sure 'num_nodes' >= 'width'
-//   or  2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
-//
-// If you don't do either of the above things, widths will be quantized to multiples
-// of small integers to guarantee the algorithm doesn't run out of temporary storage.
-//
-// If you do #2, then the non-quantized algorithm will be used, but the algorithm
-// may run out of temporary storage and be unable to pack some rectangles.
-
-STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
-// Optionally call this function after init but before doing any packing to
-// change the handling of the out-of-temp-memory scenario, described above.
-// If you call init again, this will be reset to the default (false).
-
-
-STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
-// Optionally select which packing heuristic the library should use. Different
-// heuristics will produce better/worse results for different data sets.
-// If you call init again, this will be reset to the default.
-
-enum
-{
-   STBRP_HEURISTIC_Skyline_default=0,
-   STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
-   STBRP_HEURISTIC_Skyline_BF_sortHeight
-};
-
-
-//////////////////////////////////////////////////////////////////////////////
-//
-// the details of the following structures don't matter to you, but they must
-// be visible so you can handle the memory allocations for them
-
-struct stbrp_node
-{
-   stbrp_coord  x,y;
-   stbrp_node  *next;
-};
-
-struct stbrp_context
-{
-   int width;
-   int height;
-   int align;
-   int init_mode;
-   int heuristic;
-   int num_nodes;
-   stbrp_node *active_head;
-   stbrp_node *free_head;
-   stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
-};
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
index 996601d9c6cf4e3f4ff1b4b0feedcc5869b5a880..af6704a5561e94013dfd7cf1a98d7f3ef912d22c 100644 (file)
 #include "gskglshaderprivate.h"
 #include "gskdebugprivate.h"
 
-#include "gl/gskglrendererprivate.h"
 #include "ngl/gsknglrendererprivate.h"
 
 static GskGLUniformType
@@ -544,9 +543,7 @@ gsk_gl_shader_compile (GskGLShader  *shader,
 {
   g_return_val_if_fail (GSK_IS_GL_SHADER (shader), FALSE);
 
-  if (GSK_IS_GL_RENDERER (renderer))
-    return gsk_gl_renderer_try_compile_gl_shader (GSK_GL_RENDERER (renderer), shader, error);
-  else if (GSK_IS_NGL_RENDERER (renderer))
+  if (GSK_IS_NGL_RENDERER (renderer))
     return gsk_ngl_renderer_try_compile_gl_shader (GSK_NGL_RENDERER (renderer), shader, error);
 
   g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
index 082ec4c1e8e4d985afbdd825b82d5da5b9ad8d66..77fc9a0dfa769d047b857f231d772e8664648042 100644 (file)
@@ -38,7 +38,6 @@
 
 #include "gskcairorenderer.h"
 #include "gskdebugprivate.h"
-#include "gl/gskglrenderer.h"
 #include "ngl/gsknglrenderer.h"
 #include "gskprofilerprivate.h"
 #include "gskrendernodeprivate.h"
@@ -508,8 +507,6 @@ get_renderer_for_name (const char *renderer_name)
   else if (g_ascii_strcasecmp (renderer_name, "opengl") == 0 ||
            g_ascii_strcasecmp (renderer_name, "ngl") == 0)
     return GSK_TYPE_NGL_RENDERER;
-  else if (g_ascii_strcasecmp (renderer_name, "gl") == 0)
-    return GSK_TYPE_GL_RENDERER;
 #ifdef GDK_RENDERING_VULKAN
   else if (g_ascii_strcasecmp (renderer_name, "vulkan") == 0)
     return GSK_TYPE_VULKAN_RENDERER;
@@ -520,12 +517,11 @@ get_renderer_for_name (const char *renderer_name)
 #ifdef GDK_WINDOWING_BROADWAY
       g_print ("broadway - Use the Broadway specific renderer\n");
 #else
-      g_print ("broadway - disabled during GTK build\n");
+      g_print ("broadway - Disabled during GTK build\n");
 #endif
       g_print ("   cairo - Use the Cairo fallback renderer\n");
       g_print ("  opengl - Use the default OpenGL renderer\n");
-      g_print ("      gl - An OpenGL renderer\n");
-      g_print ("     ngl - Another OpenGL renderer\n");
+      g_print ("     ngl - An OpenGL renderer\n");
 #ifdef GDK_RENDERING_VULKAN
       g_print ("  vulkan - Use the Vulkan renderer\n");
 #else
index 7b82108286df4d8c7f7c8242ad2c02aee0a3ec39..20fd33185d73c63dd56ba44c66bb36846f0ad737 100644 (file)
@@ -1,25 +1,3 @@
-gsk_private_gl_shaders = [
-  'gl/resources/preamble.glsl',
-  'gl/resources/preamble.fs.glsl',
-  'gl/resources/preamble.vs.glsl',
-  'gl/resources/border.glsl',
-  'gl/resources/blit.glsl',
-  'gl/resources/coloring.glsl',
-  'gl/resources/color.glsl',
-  'gl/resources/linear_gradient.glsl',
-  'gl/resources/radial_gradient.glsl',
-  'gl/resources/conic_gradient.glsl',
-  'gl/resources/color_matrix.glsl',
-  'gl/resources/blur.glsl',
-  'gl/resources/inset_shadow.glsl',
-  'gl/resources/outset_shadow.glsl',
-  'gl/resources/unblurred_outset_shadow.glsl',
-  'gl/resources/cross_fade.glsl',
-  'gl/resources/blend.glsl',
-  'gl/resources/repeat.glsl',
-  'gl/resources/custom.glsl',
-]
-
 gsk_private_ngl_shaders = [
   'ngl/resources/preamble.glsl',
   'ngl/resources/preamble.fs.glsl',
@@ -53,7 +31,6 @@ gsk_public_sources = files([
   'gskrendernodeparser.c',
   'gskroundedrect.c',
   'gsktransform.c',
-  'gl/gskglrenderer.c',
   'ngl/gsknglrenderer.c',
 ])
 
@@ -62,16 +39,6 @@ gsk_private_sources = files([
   'gskdebug.c',
   'gskprivate.c',
   'gskprofiler.c',
-  'gl/gskglshaderbuilder.c',
-  'gl/gskglprofiler.c',
-  'gl/gskglglyphcache.c',
-  'gl/gskgldriver.c',
-  'gl/gskglrenderops.c',
-  'gl/gskglshadowcache.c',
-  'gl/gskgltextureatlas.c',
-  'gl/gskgliconcache.c',
-  'gl/opbuffer.c',
-  'gl/stb_rect_pack.c',
   'ngl/gsknglattachmentstate.c',
   'ngl/gsknglbuffer.c',
   'ngl/gsknglcommandqueue.c',
@@ -85,6 +52,8 @@ gsk_private_sources = files([
   'ngl/gskngltexturelibrary.c',
   'ngl/gskngluniformstate.c',
   'ngl/gskngltexturepool.c',
+  'ngl/gskglprofiler.c',
+  'ngl/stb_rect_pack.c',
   'ngl/fp16.c',
 ])
 
@@ -106,7 +75,6 @@ gsk_public_headers = files([
 install_headers(gsk_public_headers, 'gsk.h', subdir: 'gtk-4.0/gsk')
 
 gsk_public_gl_headers = files([
-  'gl/gskglrenderer.h',
   'ngl/gsknglrenderer.h',
 ])
 install_headers(gsk_public_gl_headers, subdir: 'gtk-4.0/gsk/gl')
@@ -177,7 +145,6 @@ gsk_resources_xml = configure_file(output: 'gsk.resources.xml',
   command: [
     find_program('gen-gsk-gresources-xml.py'),
     '@OUTPUT@',
-    gsk_private_gl_shaders,
     gsk_private_ngl_shaders,
     gsk_private_vulkan_compiled_shaders,
     gsk_private_vulkan_shaders
diff --git a/gsk/ngl/gskglprofiler.c b/gsk/ngl/gskglprofiler.c
new file mode 100644 (file)
index 0000000..9b834e5
--- /dev/null
@@ -0,0 +1,181 @@
+#include "config.h"
+
+#include "gskglprofilerprivate.h"
+
+#include <epoxy/gl.h>
+
+#define N_QUERIES       4
+
+struct _GskGLProfiler
+{
+  GObject parent_instance;
+
+  GdkGLContext *gl_context;
+
+  /* Creating GL queries is kind of expensive, so we pay the
+   * price upfront and create a circular buffer of queries
+   */
+  GLuint gl_queries[N_QUERIES];
+  GLuint active_query;
+
+  gboolean has_queries : 1;
+  gboolean has_timer : 1;
+  gboolean first_frame : 1;
+};
+
+enum {
+  PROP_GL_CONTEXT = 1,
+
+  N_PROPERTIES
+};
+
+static GParamSpec *gsk_gl_profiler_properties[N_PROPERTIES];
+
+G_DEFINE_TYPE (GskGLProfiler, gsk_gl_profiler, G_TYPE_OBJECT)
+
+static void
+gsk_gl_profiler_finalize (GObject *gobject)
+{
+  GskGLProfiler *self = GSK_GL_PROFILER (gobject);
+
+  if (self->has_queries)
+    glDeleteQueries (N_QUERIES, self->gl_queries);
+
+  g_clear_object (&self->gl_context);
+
+  G_OBJECT_CLASS (gsk_gl_profiler_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_gl_profiler_set_property (GObject      *gobject,
+                              guint         prop_id,
+                              const GValue *value,
+                              GParamSpec   *pspec)
+{
+  GskGLProfiler *self = GSK_GL_PROFILER (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_GL_CONTEXT:
+      self->gl_context = g_value_dup_object (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+    }
+}
+
+static void
+gsk_gl_profiler_get_property (GObject    *gobject,
+                              guint       prop_id,
+                              GValue     *value,
+                              GParamSpec *pspec)
+{
+  GskGLProfiler *self = GSK_GL_PROFILER (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_GL_CONTEXT:
+      g_value_set_object (value, self->gl_context);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+    }
+}
+
+static void
+gsk_gl_profiler_class_init (GskGLProfilerClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->set_property = gsk_gl_profiler_set_property;
+  gobject_class->get_property = gsk_gl_profiler_get_property;
+  gobject_class->finalize = gsk_gl_profiler_finalize;
+
+  gsk_gl_profiler_properties[PROP_GL_CONTEXT] =
+    g_param_spec_object ("gl-context",
+                         "GL Context",
+                         "The GdkGLContext used by the GL profiler",
+                         GDK_TYPE_GL_CONTEXT,
+                         G_PARAM_READWRITE |
+                         G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (gobject_class, N_PROPERTIES, gsk_gl_profiler_properties);
+}
+
+static void
+gsk_gl_profiler_init (GskGLProfiler *self)
+{
+  self->has_queries = epoxy_is_desktop_gl();
+  self->has_timer = epoxy_is_desktop_gl() && (epoxy_gl_version () >= 33 || epoxy_has_gl_extension ("GL_ARB_timer_query"));
+
+  if (!self->has_queries)
+    return;
+
+  glGenQueries (N_QUERIES, self->gl_queries);
+  self->first_frame = TRUE;
+}
+
+GskGLProfiler *
+gsk_gl_profiler_new (GdkGLContext *context)
+{
+  g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
+
+  return g_object_new (GSK_TYPE_GL_PROFILER, "gl-context", context, NULL);
+}
+
+void
+gsk_gl_profiler_begin_gpu_region (GskGLProfiler *profiler)
+{
+  GLuint query_id;
+
+  g_return_if_fail (GSK_IS_GL_PROFILER (profiler));
+
+  if (!profiler->has_timer || !profiler->has_queries)
+    return;
+
+  query_id = profiler->gl_queries[profiler->active_query];
+  glBeginQuery (GL_TIME_ELAPSED, query_id);
+}
+
+guint64
+gsk_gl_profiler_end_gpu_region (GskGLProfiler *profiler)
+{
+  GLuint last_query_id;
+  GLint res;
+  GLuint64 elapsed;
+
+  g_return_val_if_fail (GSK_IS_GL_PROFILER (profiler), 0);
+
+  if (!profiler->has_timer || !profiler->has_queries)
+    return 0;
+
+  glEndQuery (GL_TIME_ELAPSED);
+
+  if (profiler->active_query == 0)
+    last_query_id = N_QUERIES - 1;
+  else
+    last_query_id = profiler->active_query - 1;
+
+  /* Advance iterator */
+  profiler->active_query += 1;
+  if (profiler->active_query == N_QUERIES)
+    profiler->active_query = 0;
+
+  /* If this is the first frame we already have a result */
+  if (profiler->first_frame)
+    {
+      profiler->first_frame = FALSE;
+      return 0;
+    }
+
+  glGetQueryObjectiv (profiler->gl_queries[last_query_id], GL_QUERY_RESULT_AVAILABLE, &res);
+  if (res == 1)
+    glGetQueryObjectui64v (profiler->gl_queries[last_query_id], GL_QUERY_RESULT, &elapsed);
+  else
+    elapsed = 0;
+
+  return elapsed / 1000; /* Convert to usec to match other profiler APIs */
+}
diff --git a/gsk/ngl/gskglprofilerprivate.h b/gsk/ngl/gskglprofilerprivate.h
new file mode 100644 (file)
index 0000000..5b2a24b
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef __GSK_GL_PROFILER_PRIVATE_H__
+#define __GSK_GL_PROFILER_PRIVATE_H__
+
+#include <gsk/gsktypes.h>
+
+G_BEGIN_DECLS
+
+#define GSK_TYPE_GL_PROFILER (gsk_gl_profiler_get_type ())
+G_DECLARE_FINAL_TYPE (GskGLProfiler, gsk_gl_profiler, GSK, GL_PROFILER, GObject)
+
+GskGLProfiler * gsk_gl_profiler_new                     (GdkGLContext  *context);
+
+void            gsk_gl_profiler_begin_gpu_region        (GskGLProfiler *profiler);
+guint64         gsk_gl_profiler_end_gpu_region          (GskGLProfiler *profiler);
+
+G_END_DECLS
+
+#endif /* __GSK_GL_PROFILER_PRIVATE_H__ */
index a2f50c485d95be3e4689f185671c9dc6d9fd310d..b13838d48e921ea4ce8b17c72985de2cede7c811 100644 (file)
@@ -30,7 +30,7 @@
 
 #include "inlinearray.h"
 
-#include "../gl/gskglprofilerprivate.h"
+#include "gskglprofilerprivate.h"
 
 G_BEGIN_DECLS
 
index 05c2216ed7dd8aa47746f74b21185e9e3cd502e9..13e651e0d7b0e921cb662060627443310ad1417c 100644 (file)
@@ -24,7 +24,7 @@
 #include "gskngltypesprivate.h"
 #include "gskngltexturepoolprivate.h"
 
-#include "../gl/stb_rect_pack.h"
+#include "stb_rect_pack.h"
 
 G_BEGIN_DECLS
 
diff --git a/gsk/ngl/stb_rect_pack.c b/gsk/ngl/stb_rect_pack.c
new file mode 100644 (file)
index 0000000..ff65846
--- /dev/null
@@ -0,0 +1,431 @@
+
+#include "stb_rect_pack.h"
+#define STB_RECT_PACK_IMPLEMENTATION
+//////////////////////////////////////////////////////////////////////////////
+//
+//     IMPLEMENTATION SECTION
+//
+
+#ifdef STB_RECT_PACK_IMPLEMENTATION
+#ifndef STBRP_SORT
+#include <stdlib.h>
+#define STBRP_SORT qsort
+#endif
+
+#ifndef STBRP_ASSERT
+#include <assert.h>
+#define STBRP_ASSERT assert
+#endif
+
+#ifdef _MSC_VER
+#define STBRP__NOTUSED(v)  (void)(v)
+#else
+#define STBRP__NOTUSED(v)  (void)sizeof(v)
+#endif
+
+enum
+{
+   STBRP__INIT_skyline = 1
+};
+
+STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
+{
+   switch (context->init_mode) {
+      case STBRP__INIT_skyline:
+         STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
+         context->heuristic = heuristic;
+         break;
+      default:
+         STBRP_ASSERT(0);
+   }
+}
+
+STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
+{
+   if (allow_out_of_mem)
+      // if it's ok to run out of memory, then don't bother aligning them;
+      // this gives better packing, but may fail due to OOM (even though
+      // the rectangles easily fit). @TODO a smarter approach would be to only
+      // quantize once we've hit OOM, then we could get rid of this parameter.
+      context->align = 1;
+   else {
+      // if it's not ok to run out of memory, then quantize the widths
+      // so that num_nodes is always enough nodes.
+      //
+      // I.e. num_nodes * align >= width
+      //                  align >= width / num_nodes
+      //                  align = ceil(width/num_nodes)
+
+      context->align = (context->width + context->num_nodes-1) / context->num_nodes;
+   }
+}
+
+STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
+{
+   int i;
+#ifndef STBRP_LARGE_RECTS
+   STBRP_ASSERT(width <= 0xffff && height <= 0xffff);
+#endif
+
+   for (i=0; i < num_nodes-1; ++i)
+      nodes[i].next = &nodes[i+1];
+   nodes[i].next = NULL;
+   context->init_mode = STBRP__INIT_skyline;
+   context->heuristic = STBRP_HEURISTIC_Skyline_default;
+   context->free_head = &nodes[0];
+   context->active_head = &context->extra[0];
+   context->width = width;
+   context->height = height;
+   context->num_nodes = num_nodes;
+   stbrp_setup_allow_out_of_mem(context, 0);
+
+   // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
+   context->extra[0].x = 0;
+   context->extra[0].y = 0;
+   context->extra[0].next = &context->extra[1];
+   context->extra[1].x = (stbrp_coord) width;
+#ifdef STBRP_LARGE_RECTS
+   context->extra[1].y = (1<<30);
+#else
+   context->extra[1].y = 65535;
+#endif
+   context->extra[1].next = NULL;
+}
+
+// find minimum y position if it starts at x1
+static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
+{
+   stbrp_node *node = first;
+   int x1 = x0 + width;
+   int min_y, visited_width, waste_area;
+
+   STBRP__NOTUSED(c);
+
+   STBRP_ASSERT(first->x <= x0);
+
+   #if 0
+   // skip in case we're past the node
+   while (node->next->x <= x0)
+      ++node;
+   #else
+   STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
+   #endif
+
+   STBRP_ASSERT(node->x <= x0);
+
+   min_y = 0;
+   waste_area = 0;
+   visited_width = 0;
+   while (node->x < x1) {
+      if (node->y > min_y) {
+         // raise min_y higher.
+         // we've accounted for all waste up to min_y,
+         // but we'll now add more waste for everything we've visited
+         waste_area += visited_width * (node->y - min_y);
+         min_y = node->y;
+         // the first time through, visited_width might be reduced
+         if (node->x < x0)
+            visited_width += node->next->x - x0;
+         else
+            visited_width += node->next->x - node->x;
+      } else {
+         // add waste area
+         int under_width = node->next->x - node->x;
+         if (under_width + visited_width > width)
+            under_width = width - visited_width;
+         waste_area += under_width * (min_y - node->y);
+         visited_width += under_width;
+      }
+      node = node->next;
+   }
+
+   *pwaste = waste_area;
+   return min_y;
+}
+
+typedef struct
+{
+   int x,y;
+   stbrp_node **prev_link;
+} stbrp__findresult;
+
+static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
+{
+   int best_waste = (1<<30), best_x, best_y = (1 << 30);
+   stbrp__findresult fr;
+   stbrp_node **prev, *node, *tail, **best = NULL;
+
+   // align to multiple of c->align
+   width = (width + c->align - 1);
+   width -= width % c->align;
+   STBRP_ASSERT(width % c->align == 0);
+
+   node = c->active_head;
+   prev = &c->active_head;
+   while (node->x + width <= c->width) {
+      int y,waste;
+      y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
+      if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
+         // bottom left
+         if (y < best_y) {
+            best_y = y;
+            best = prev;
+         }
+      } else {
+         // best-fit
+         if (y + height <= c->height) {
+            // can only use it if it first vertically
+            if (y < best_y || (y == best_y && waste < best_waste)) {
+               best_y = y;
+               best_waste = waste;
+               best = prev;
+            }
+         }
+      }
+      prev = &node->next;
+      node = node->next;
+   }
+
+   best_x = (best == NULL) ? 0 : (*best)->x;
+
+   // if doing best-fit (BF), we also have to try aligning right edge to each node position
+   //
+   // e.g, if fitting
+   //
+   //     ____________________
+   //    |____________________|
+   //
+   //            into
+   //
+   //   |                         |
+   //   |             ____________|
+   //   |____________|
+   //
+   // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
+   //
+   // This makes BF take about 2x the time
+
+   if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
+      tail = c->active_head;
+      node = c->active_head;
+      prev = &c->active_head;
+      // find first node that's admissible
+      while (tail->x < width)
+         tail = tail->next;
+      while (tail) {
+         int xpos = tail->x - width;
+         int y,waste;
+         STBRP_ASSERT(xpos >= 0);
+         // find the left position that matches this
+         while (node->next->x <= xpos) {
+            prev = &node->next;
+            node = node->next;
+         }
+         STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
+         y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
+         if (y + height < c->height) {
+            if (y <= best_y) {
+               if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
+                  best_x = xpos;
+                  STBRP_ASSERT(y <= best_y);
+                  best_y = y;
+                  best_waste = waste;
+                  best = prev;
+               }
+            }
+         }
+         tail = tail->next;
+      }
+   }
+
+   fr.prev_link = best;
+   fr.x = best_x;
+   fr.y = best_y;
+   return fr;
+}
+
+static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
+{
+   // find best position according to heuristic
+   stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
+   stbrp_node *node, *cur;
+
+   // bail if:
+   //    1. it failed
+   //    2. the best node doesn't fit (we don't always check this)
+   //    3. we're out of memory
+   if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
+      res.prev_link = NULL;
+      return res;
+   }
+
+   // on success, create new node
+   node = context->free_head;
+   node->x = (stbrp_coord) res.x;
+   node->y = (stbrp_coord) (res.y + height);
+
+   context->free_head = node->next;
+
+   // insert the new node into the right starting point, and
+   // let 'cur' point to the remaining nodes needing to be
+   // stiched back in
+
+   cur = *res.prev_link;
+   if (cur->x < res.x) {
+      // preserve the existing one, so start testing with the next one
+      stbrp_node *next = cur->next;
+      cur->next = node;
+      cur = next;
+   } else {
+      *res.prev_link = node;
+   }
+
+   // from here, traverse cur and free the nodes, until we get to one
+   // that shouldn't be freed
+   while (cur->next && cur->next->x <= res.x + width) {
+      stbrp_node *next = cur->next;
+      // move the current node to the free list
+      cur->next = context->free_head;
+      context->free_head = cur;
+      cur = next;
+   }
+
+   // stitch the list back in
+   node->next = cur;
+
+   if (cur->x < res.x + width)
+      cur->x = (stbrp_coord) (res.x + width);
+
+#ifdef _DEBUG
+   cur = context->active_head;
+   while (cur->x < context->width) {
+      STBRP_ASSERT(cur->x < cur->next->x);
+      cur = cur->next;
+   }
+   STBRP_ASSERT(cur->next == NULL);
+
+   {
+      int count=0;
+      cur = context->active_head;
+      while (cur) {
+         cur = cur->next;
+         ++count;
+      }
+      cur = context->free_head;
+      while (cur) {
+         cur = cur->next;
+         ++count;
+      }
+      STBRP_ASSERT(count == context->num_nodes+2);
+   }
+#endif
+
+   return res;
+}
+
+static int rect_height_compare(const void *a, const void *b)
+{
+   const stbrp_rect *p = (const stbrp_rect *) a;
+   const stbrp_rect *q = (const stbrp_rect *) b;
+   if (p->h > q->h)
+      return -1;
+   if (p->h < q->h)
+      return  1;
+   return (p->w > q->w) ? -1 : (p->w < q->w);
+}
+
+static int rect_original_order(const void *a, const void *b)
+{
+   const stbrp_rect *p = (const stbrp_rect *) a;
+   const stbrp_rect *q = (const stbrp_rect *) b;
+   return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
+}
+
+#ifdef STBRP_LARGE_RECTS
+#define STBRP__MAXVAL  0xffffffff
+#else
+#define STBRP__MAXVAL  0xffff
+#endif
+
+STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
+{
+   int i, all_rects_packed = 1;
+
+   // we use the 'was_packed' field internally to allow sorting/unsorting
+   for (i=0; i < num_rects; ++i) {
+      rects[i].was_packed = i;
+   }
+
+   // sort according to heuristic
+   STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
+
+   for (i=0; i < num_rects; ++i) {
+      if (rects[i].w == 0 || rects[i].h == 0) {
+         rects[i].x = rects[i].y = 0;  // empty rect needs no space
+      } else {
+         stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
+         if (fr.prev_link) {
+            rects[i].x = (stbrp_coord) fr.x;
+            rects[i].y = (stbrp_coord) fr.y;
+         } else {
+            rects[i].x = rects[i].y = STBRP__MAXVAL;
+         }
+      }
+   }
+
+   // unsort
+   STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
+
+   // set was_packed flags and all_rects_packed status
+   for (i=0; i < num_rects; ++i) {
+      rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
+      if (!rects[i].was_packed)
+         all_rects_packed = 0;
+   }
+
+   // return the all_rects_packed status
+   return all_rects_packed;
+}
+#endif
+
+/*
+------------------------------------------------------------------------------
+This software is available under 2 licenses -- choose whichever you prefer.
+------------------------------------------------------------------------------
+ALTERNATIVE A - MIT License
+Copyright (c) 2017 Sean Barrett
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+------------------------------------------------------------------------------
+ALTERNATIVE B - Public Domain (www.unlicense.org)
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------------
+*/
diff --git a/gsk/ngl/stb_rect_pack.h b/gsk/ngl/stb_rect_pack.h
new file mode 100644 (file)
index 0000000..3ecb1c2
--- /dev/null
@@ -0,0 +1,191 @@
+// stb_rect_pack.h - v0.99 - public domain - rectangle packing
+// Sean Barrett 2014
+//
+// Useful for e.g. packing rectangular textures into an atlas.
+// Does not do rotation.
+//
+// Not necessarily the awesomest packing method, but better than
+// the totally naive one in stb_truetype (which is primarily what
+// this is meant to replace).
+//
+// Has only had a few tests run, may have issues.
+//
+// More docs to come.
+//
+// No memory allocations; uses qsort() and assert() from stdlib.
+// Can override those by defining STBRP_SORT and STBRP_ASSERT.
+//
+// This library currently uses the Skyline Bottom-Left algorithm.
+//
+// Please note: better rectangle packers are welcome! Please
+// implement them to the same API, but with a different init
+// function.
+//
+// Credits
+//
+//  Library
+//    Sean Barrett
+//  Minor features
+//    Martins Mozeiko
+//    github:IntellectualKitty
+//
+//  Bugfixes / warning fixes
+//    Jeremy Jaussaud
+//
+// Version history:
+//
+//     0.99  (2019-02-07)  warning fixes
+//     0.11  (2017-03-03)  return packing success/fail result
+//     0.10  (2016-10-25)  remove cast-away-const to avoid warnings
+//     0.09  (2016-08-27)  fix compiler warnings
+//     0.08  (2015-09-13)  really fix bug with empty rects (w=0 or h=0)
+//     0.07  (2015-09-13)  fix bug with empty rects (w=0 or h=0)
+//     0.06  (2015-04-15)  added STBRP_SORT to allow replacing qsort
+//     0.05:  added STBRP_ASSERT to allow replacing assert
+//     0.04:  fixed minor bug in STBRP_LARGE_RECTS support
+//     0.01:  initial release
+//
+// LICENSE
+//
+//   See end of file for license information.
+
+//////////////////////////////////////////////////////////////////////////////
+//
+//       INCLUDE SECTION
+//
+
+#ifndef STB_INCLUDE_STB_RECT_PACK_H
+#define STB_INCLUDE_STB_RECT_PACK_H
+
+#define STB_RECT_PACK_VERSION  1
+
+#ifdef STBRP_STATIC
+#define STBRP_DEF static
+#else
+#define STBRP_DEF extern
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct stbrp_context stbrp_context;
+typedef struct stbrp_node    stbrp_node;
+typedef struct stbrp_rect    stbrp_rect;
+
+#ifdef STBRP_LARGE_RECTS
+typedef int            stbrp_coord;
+#else
+typedef unsigned short stbrp_coord;
+#endif
+
+STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
+// Assign packed locations to rectangles. The rectangles are of type
+// 'stbrp_rect' defined below, stored in the array 'rects', and there
+// are 'num_rects' many of them.
+//
+// Rectangles which are successfully packed have the 'was_packed' flag
+// set to a non-zero value and 'x' and 'y' store the minimum location
+// on each axis (i.e. bottom-left in cartesian coordinates, top-left
+// if you imagine y increasing downwards). Rectangles which do not fit
+// have the 'was_packed' flag set to 0.
+//
+// You should not try to access the 'rects' array from another thread
+// while this function is running, as the function temporarily reorders
+// the array while it executes.
+//
+// To pack into another rectangle, you need to call stbrp_init_target
+// again. To continue packing into the same rectangle, you can call
+// this function again. Calling this multiple times with multiple rect
+// arrays will probably produce worse packing results than calling it
+// a single time with the full rectangle array, but the option is
+// available.
+//
+// The function returns 1 if all of the rectangles were successfully
+// packed and 0 otherwise.
+
+struct stbrp_rect
+{
+   // reserved for your use:
+   int            id;
+
+   // input:
+   stbrp_coord    w, h;
+
+   // output:
+   stbrp_coord    x, y;
+   int            was_packed;  // non-zero if valid packing
+
+}; // 16 bytes, nominally
+
+
+STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
+// Initialize a rectangle packer to:
+//    pack a rectangle that is 'width' by 'height' in dimensions
+//    using temporary storage provided by the array 'nodes', which is 'num_nodes' long
+//
+// You must call this function every time you start packing into a new target.
+//
+// There is no "shutdown" function. The 'nodes' memory must stay valid for
+// the following stbrp_pack_rects() call (or calls), but can be freed after
+// the call (or calls) finish.
+//
+// Note: to guarantee best results, either:
+//       1. make sure 'num_nodes' >= 'width'
+//   or  2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
+//
+// If you don't do either of the above things, widths will be quantized to multiples
+// of small integers to guarantee the algorithm doesn't run out of temporary storage.
+//
+// If you do #2, then the non-quantized algorithm will be used, but the algorithm
+// may run out of temporary storage and be unable to pack some rectangles.
+
+STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
+// Optionally call this function after init but before doing any packing to
+// change the handling of the out-of-temp-memory scenario, described above.
+// If you call init again, this will be reset to the default (false).
+
+
+STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
+// Optionally select which packing heuristic the library should use. Different
+// heuristics will produce better/worse results for different data sets.
+// If you call init again, this will be reset to the default.
+
+enum
+{
+   STBRP_HEURISTIC_Skyline_default=0,
+   STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
+   STBRP_HEURISTIC_Skyline_BF_sortHeight
+};
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// the details of the following structures don't matter to you, but they must
+// be visible so you can handle the memory allocations for them
+
+struct stbrp_node
+{
+   stbrp_coord  x,y;
+   stbrp_node  *next;
+};
+
+struct stbrp_context
+{
+   int width;
+   int height;
+   int align;
+   int init_mode;
+   int heuristic;
+   int num_nodes;
+   stbrp_node *active_head;
+   stbrp_node *free_head;
+   stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+